Respect max fps if specified in the request.
Sleep for appropriate amount of time before acquiring new image
from Surface in case acquiring image imediatelly would exceed max fps
specified by the request.
Bug: 338251124
Test: atest CtsVirtualDevicesCameraCtsTestCases:android.hardware.camera2.cts.CaptureRequestTest#testNoiseReductionModeControl[1]
Change-Id: I1ac504f05cef044b81a2531074e1bedd77412805
diff --git a/services/camera/virtualcamera/VirtualCameraRenderThread.cc b/services/camera/virtualcamera/VirtualCameraRenderThread.cc
index ca62cce..a5f67b0 100644
--- a/services/camera/virtualcamera/VirtualCameraRenderThread.cc
+++ b/services/camera/virtualcamera/VirtualCameraRenderThread.cc
@@ -14,7 +14,6 @@
* limitations under the License.
*/
-#include "hardware/gralloc.h"
#define LOG_TAG "VirtualCameraRenderThread"
#include "VirtualCameraRenderThread.h"
@@ -45,6 +44,7 @@
#include "android-base/thread_annotations.h"
#include "android/binder_auto_utils.h"
#include "android/hardware_buffer.h"
+#include "hardware/gralloc.h"
#include "system/camera_metadata.h"
#include "ui/GraphicBuffer.h"
#include "ui/Rect.h"
@@ -422,9 +422,38 @@
void VirtualCameraRenderThread::processCaptureRequest(
const ProcessCaptureRequestTask& request) {
- const std::chrono::nanoseconds timestamp =
+ if (mTestMode) {
+ // In test mode let's just render something to the Surface ourselves.
+ renderTestPatternYCbCr420(mEglSurfaceTexture->getSurface(),
+ request.getFrameNumber());
+ }
+
+ std::chrono::nanoseconds timestamp =
std::chrono::duration_cast<std::chrono::nanoseconds>(
std::chrono::steady_clock::now().time_since_epoch());
+ std::chrono::nanoseconds lastAcquisitionTimestamp(
+ mLastAcquisitionTimestampNanoseconds.exchange(timestamp.count(),
+ std::memory_order_relaxed));
+
+ if (request.getRequestSettings().fpsRange) {
+ const int maxFps =
+ std::min(1, request.getRequestSettings().fpsRange->maxFps);
+ const std::chrono::nanoseconds minFrameDuration(
+ static_cast<uint64_t>(1e9 / maxFps));
+ std::chrono::nanoseconds frameDuration =
+ timestamp - lastAcquisitionTimestamp;
+ if (frameDuration < minFrameDuration) {
+ // We're too fast for the configured maxFps, let's wait a bit.
+ std::this_thread::sleep_for(minFrameDuration - frameDuration);
+ timestamp = std::chrono::duration_cast<std::chrono::nanoseconds>(
+ std::chrono::steady_clock::now().time_since_epoch());
+ mLastAcquisitionTimestampNanoseconds.store(timestamp.count(),
+ std::memory_order_relaxed);
+ }
+ }
+
+ // Acquire new (most recent) image from the Surface.
+ mEglSurfaceTexture->updateTexture();
CaptureResult captureResult;
captureResult.fmqResultSize = 0;
@@ -439,14 +468,6 @@
const std::vector<CaptureRequestBuffer>& buffers = request.getBuffers();
captureResult.outputBuffers.resize(buffers.size());
- if (mTestMode) {
- // In test mode let's just render something to the Surface ourselves.
- renderTestPatternYCbCr420(mEglSurfaceTexture->getSurface(),
- request.getFrameNumber());
- }
-
- mEglSurfaceTexture->updateTexture();
-
for (int i = 0; i < buffers.size(); ++i) {
const CaptureRequestBuffer& reqBuffer = buffers[i];
StreamBuffer& resBuffer = captureResult.outputBuffers[i];