diff --git a/services/camera/libcameraservice/api2/HeicCompositeStream.cpp b/services/camera/libcameraservice/api2/HeicCompositeStream.cpp index bf4d1c8e43..9cdad700fe 100644 --- a/services/camera/libcameraservice/api2/HeicCompositeStream.cpp +++ b/services/camera/libcameraservice/api2/HeicCompositeStream.cpp @@ -67,6 +67,7 @@ HeicCompositeStream::HeicCompositeStream(wp 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 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 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; diff --git a/services/camera/libcameraservice/api2/HeicCompositeStream.h b/services/camera/libcameraservice/api2/HeicCompositeStream.h index 04e7b83c20..e88471d74d 100644 --- a/services/camera/libcameraservice/api2/HeicCompositeStream.h +++ b/services/camera/libcameraservice/api2/HeicCompositeStream.h @@ -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 mCodecOutputBuffers; std::queue mCodecOutputBufferTimestamps; size_t mCodecOutputCounter; + int32_t mQuality; // Keep all incoming Yuv buffer pending tiling and encoding (for HEVC YUV tiling only) std::vector mInputYuvBuffers;