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

Commit f7da096d authored by Zhijun He's avatar Zhijun He
Browse files

Camera3: scale the max jpeg buffer size based on resolutions

The max jpeg buffer size was always the android.jpeg.maxSize, regardless of
the actual jpeg capture size. This creates a huge memory waste especially
for smaller size jpeg capture. Now the max jpeg buffer is linearly scaled based
on the resolution.

Bug: 14288983
Change-Id: I8a971b8e2f4fc7fec0154547bdb688579af71a47
parent 67ee990d
Loading
Loading
Loading
Loading
+57 −1
Original line number Diff line number Diff line
@@ -284,6 +284,53 @@ bool Camera3Device::tryLockSpinRightRound(Mutex& lock) {
    return gotLock;
}

ssize_t Camera3Device::getJpegBufferSize(uint32_t width, uint32_t height) const {
    // TODO: replace below with availableStreamConfiguration for HAL3.2+.
    camera_metadata_ro_entry availableJpegSizes =
            mDeviceInfo.find(ANDROID_SCALER_AVAILABLE_JPEG_SIZES);
    if (availableJpegSizes.count == 0 || availableJpegSizes.count % 2 != 0) {
        ALOGE("%s: Camera %d: Can't find find valid available jpeg sizes in static metadata!",
                __FUNCTION__, mId);
        return BAD_VALUE;
    }

    // Get max jpeg size (area-wise).
    int32_t maxJpegWidth = 0, maxJpegHeight = 0;
    bool foundMax = false;
    for (size_t i = 0; i < availableJpegSizes.count; i += 2) {
        if ((availableJpegSizes.data.i32[i] * availableJpegSizes.data.i32[i + 1])
                > (maxJpegWidth * maxJpegHeight)) {
            maxJpegWidth = availableJpegSizes.data.i32[i];
            maxJpegHeight = availableJpegSizes.data.i32[i + 1];
            foundMax = true;
        }
    }
    if (!foundMax) {
        return BAD_VALUE;
    }

    // Get max jpeg buffer size
    ssize_t maxJpegBufferSize = 0;
    camera_metadata_ro_entry jpegMaxSize = mDeviceInfo.find(ANDROID_JPEG_MAX_SIZE);
    if (jpegMaxSize.count == 0) {
        ALOGE("%s: Camera %d: Can't find maximum JPEG size in static metadata!", __FUNCTION__, mId);
        return BAD_VALUE;
    }
    maxJpegBufferSize = jpegMaxSize.data.i32[0];

    // Calculate final jpeg buffer size for the given resolution.
    float scaleFactor = ((float) (width * height)) / (maxJpegWidth * maxJpegHeight);
    ssize_t jpegBufferSize = scaleFactor * maxJpegBufferSize;
    // Bound the buffer size to [MIN_JPEG_BUFFER_SIZE, maxJpegBufferSize].
    if (jpegBufferSize > maxJpegBufferSize) {
        jpegBufferSize = maxJpegBufferSize;
    } else if (jpegBufferSize < kMinJpegBufferSize) {
        jpegBufferSize = kMinJpegBufferSize;
    }

    return jpegBufferSize;
}

status_t Camera3Device::dump(int fd, const Vector<String16> &args) {
    ATRACE_CALL();
    (void)args;
@@ -741,8 +788,17 @@ status_t Camera3Device::createStream(sp<ANativeWindow> consumer,

    sp<Camera3OutputStream> newStream;
    if (format == HAL_PIXEL_FORMAT_BLOB) {
        ssize_t jpegBufferSize = getJpegBufferSize(width, height);
        if (jpegBufferSize > 0) {
            ALOGV("%s: Overwrite Jpeg output buffer size from %zu to %zu",
                    __FUNCTION__, size, jpegBufferSize);
        } else {
            SET_ERR_L("Invalid jpeg buffer size %zd", jpegBufferSize);
            return BAD_VALUE;
        }

        newStream = new Camera3OutputStream(mNextStreamId, consumer,
                width, height, size, format);
                width, height, jpegBufferSize, format);
    } else {
        newStream = new Camera3OutputStream(mNextStreamId, consumer,
                width, height, format);
+10 −1
Original line number Diff line number Diff line
@@ -93,7 +93,8 @@ class Camera3Device :

    // Actual stream creation/deletion is delayed until first request is submitted
    // If adding streams while actively capturing, will pause device before adding
    // stream, reconfiguring device, and unpausing.
    // stream, reconfiguring device, and unpausing. Note that, for JPEG stream, the
    // buffer size may be overwritten by an more accurate value calculated by Camera3Device.
    virtual status_t createStream(sp<ANativeWindow> consumer,
            uint32_t width, uint32_t height, int format, size_t size,
            int *id);
@@ -144,6 +145,8 @@ class Camera3Device :
    static const nsecs_t       kShutdownTimeout   = 5000000000; // 5 sec
    static const nsecs_t       kActiveTimeout     = 500000000;  // 500 ms
    struct                     RequestTrigger;
    // minimal jpeg buffer size: 256KB + blob header
    static const ssize_t       kMinJpegBufferSize = 256 * 1024 + sizeof(camera3_jpeg_blob);

    // A lock to enforce serialization on the input/configure side
    // of the public interface.
@@ -294,6 +297,12 @@ class Camera3Device :
     */
    bool               tryLockSpinRightRound(Mutex& lock);

    /**
     * Get Jpeg buffer size for a given jpeg resolution.
     * Negative values are error codes.
     */
    ssize_t             getJpegBufferSize(uint32_t width, uint32_t height) const;

    struct RequestTrigger {
        // Metadata tag number, e.g. android.control.aePrecaptureTrigger
        uint32_t metadataTag;