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

Commit 62f49ed0 authored by Shuzhen Wang's avatar Shuzhen Wang
Browse files

Camera: Heic: Update codec quality per shot

Update codec quality setting at the time of:
- Input pending frame creation if there is no inflight encoding.
- Any pending input frame is done processing.

Note that since there is no way for camera framework to synchronize
quality setting per-frame when encoder runs in surface mode, the update
of quality is on best-effort basis.

Test: vendor testing, and camera CTS
Bug: 140506016
Change-Id: I58ddc9302b1507428ccf42f4c77c6624f1c600ba
parent b7b2f5d8
Loading
Loading
Loading
Loading
+35 −11
Original line number Diff line number Diff line
@@ -67,6 +67,7 @@ HeicCompositeStream::HeicCompositeStream(wp<CameraDeviceBase> device,
        mDequeuedOutputBufferCnt(0),
        mLockedAppSegmentBufferCnt(0),
        mCodecOutputCounter(0),
        mQuality(-1),
        mGridTimestampUs(0) {
}

@@ -525,6 +526,12 @@ void HeicCompositeStream::compilePendingInputLocked() {
        mPendingInputFrames[it->first].orientation = it->second.first;
        mPendingInputFrames[it->first].quality = it->second.second;
        mSettingsByTimestamp.erase(it);

        // Set encoder quality if no inflight encoding
        if (mPendingInputFrames.size() == 1) {
            int32_t newQuality = mPendingInputFrames.begin()->second.quality;
            updateCodecQualityLocked(newQuality);
        }
    }

    while (!mInputAppSegmentBuffers.empty()) {
@@ -851,17 +858,6 @@ status_t HeicCompositeStream::startMuxerForInputFrame(nsecs_t timestamp, InputFr
                strerror(-res), res);
        return res;
    }
    // Set encoder quality
    {
        sp<AMessage> qualityParams = new AMessage;
        qualityParams->setInt32(PARAMETER_KEY_VIDEO_BITRATE, inputFrame.quality);
        res = mCodec->setParameters(qualityParams);
        if (res != OK) {
            ALOGE("%s: Failed to set codec quality: %s (%d)",
                    __FUNCTION__, strerror(-res), res);
            return res;
        }
    }

    ssize_t trackId = inputFrame.muxer->addTrack(inputFrame.format);
    if (trackId < 0) {
@@ -1148,16 +1144,30 @@ void HeicCompositeStream::releaseInputFrameLocked(InputFrame *inputFrame /*out*/

void HeicCompositeStream::releaseInputFramesLocked() {
    auto it = mPendingInputFrames.begin();
    bool inputFrameDone = false;
    while (it != mPendingInputFrames.end()) {
        auto& inputFrame = it->second;
        if (inputFrame.error ||
            (inputFrame.appSegmentWritten && inputFrame.pendingOutputTiles == 0)) {
            releaseInputFrameLocked(&inputFrame);
            it = mPendingInputFrames.erase(it);
            inputFrameDone = true;
        } else {
            it++;
        }
    }

    // Update codec quality based on first upcoming input frame.
    // Note that when encoding is in surface mode, currently there is  no
    // way for camera service to synchronize quality setting on a per-frame
    // basis: we don't get notification when codec is ready to consume a new
    // input frame. So we update codec quality on a best-effort basis.
    if (inputFrameDone) {
        auto firstPendingFrame = mPendingInputFrames.begin();
        if (firstPendingFrame != mPendingInputFrames.end()) {
            updateCodecQualityLocked(firstPendingFrame->second.quality);
        }
    }
}

status_t HeicCompositeStream::initializeCodec(uint32_t width, uint32_t height,
@@ -1546,6 +1556,20 @@ size_t HeicCompositeStream::calcAppSegmentMaxSize(const CameraMetadata& info) {
    return maxAppsSegment * (2 + 0xFFFF) + sizeof(struct CameraBlob);
}

void HeicCompositeStream::updateCodecQualityLocked(int32_t quality) {
    if (quality != mQuality) {
        sp<AMessage> qualityParams = new AMessage;
        qualityParams->setInt32(PARAMETER_KEY_VIDEO_BITRATE, quality);
        status_t res = mCodec->setParameters(qualityParams);
        if (res != OK) {
            ALOGE("%s: Failed to set codec quality: %s (%d)",
                    __FUNCTION__, strerror(-res), res);
        } else {
            mQuality = quality;
        }
    }
}

bool HeicCompositeStream::threadLoop() {
    int64_t currentTs = INT64_MAX;
    bool newInputAvailable = false;
+2 −0
Original line number Diff line number Diff line
@@ -199,6 +199,7 @@ private:
            size_t top, size_t left, size_t width, size_t height);
    void initCopyRowFunction(int32_t width);
    static size_t calcAppSegmentMaxSize(const CameraMetadata& info);
    void updateCodecQualityLocked(int32_t quality);

    static const nsecs_t kWaitDuration = 10000000; // 10 ms
    static const int32_t kDefaultJpegQuality = 99;
@@ -240,6 +241,7 @@ private:
    std::vector<CodecOutputBufferInfo> mCodecOutputBuffers;
    std::queue<int64_t> mCodecOutputBufferTimestamps;
    size_t mCodecOutputCounter;
    int32_t mQuality;

    // Keep all incoming Yuv buffer pending tiling and encoding (for HEVC YUV tiling only)
    std::vector<int64_t> mInputYuvBuffers;