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

Commit c944886e authored by Ján Sebechlebský's avatar Ján Sebechlebský Committed by Android (Google) Code Review
Browse files

Merge "Wait for next available frame" into main

parents 69d424d9 b828267e
Loading
Loading
Loading
Loading
+12 −7
Original line number Diff line number Diff line
@@ -73,13 +73,14 @@ const char* kDevicePathPrefix = "device@1.1/virtual/";

constexpr int32_t kMaxJpegSize = 3 * 1024 * 1024 /*3MiB*/;

constexpr int32_t kMinFps = 15;

constexpr std::chrono::nanoseconds kMaxFrameDuration =
    std::chrono::duration_cast<std::chrono::nanoseconds>(1e9ns / kMinFps);
    std::chrono::duration_cast<std::chrono::nanoseconds>(
        1e9ns / VirtualCameraDevice::kMinFps);

constexpr uint8_t kPipelineMaxDepth = 2;

constexpr int k30Fps = 30;

constexpr MetadataBuilder::ControlRegion kDefaultEmptyControlRegion{};

const std::array<Resolution, 5> kStandardJpegThumbnailSizes{
@@ -130,16 +131,20 @@ std::vector<FpsRange> fpsRangesForInputConfig(
  std::set<FpsRange> availableRanges;

  for (const SupportedStreamConfiguration& config : configs) {
    availableRanges.insert({.minFps = kMinFps, .maxFps = config.maxFps});
    availableRanges.insert(
        {.minFps = VirtualCameraDevice::kMinFps, .maxFps = config.maxFps});
    availableRanges.insert({.minFps = config.maxFps, .maxFps = config.maxFps});
  }

  if (std::any_of(configs.begin(), configs.end(),
                  [](const SupportedStreamConfiguration& config) {
                    return config.maxFps >= 30;
                    return config.maxFps >= k30Fps;
                  })) {
    availableRanges.insert({.minFps = kMinFps, .maxFps = 30});
    availableRanges.insert({.minFps = 30, .maxFps = 30});
    // Extend the set of available ranges with (minFps <= 15, 30) & (30, 30) as
    // required by CDD.
    availableRanges.insert(
        {.minFps = VirtualCameraDevice::kMinFps, .maxFps = k30Fps});
    availableRanges.insert({.minFps = k30Fps, .maxFps = k30Fps});
  }

  return std::vector<FpsRange>(availableRanges.begin(), availableRanges.end());
+4 −0
Original line number Diff line number Diff line
@@ -126,6 +126,10 @@ class VirtualCameraDevice
  // Default JPEG orientation.
  static constexpr uint8_t kDefaultJpegOrientation = 0;

  // TODO(b/342674104) CDD requires <= 15.
  // Change this to lower value after confirming it doesn't cause any issue (timeouts).
  static constexpr int kMinFps = 15;

  // Default Make and Model for Exif
  static constexpr char kDefaultMakeAndModel[] = "Android Virtual Camera";

+34 −1
Original line number Diff line number Diff line
@@ -277,6 +277,16 @@ std::vector<uint8_t> createExif(
  return app1Data;
}

std::chrono::nanoseconds getMaxFrameDuration(
    const RequestSettings& requestSettings) {
  if (requestSettings.fpsRange.has_value()) {
    return std::chrono::nanoseconds(static_cast<uint64_t>(
        1e9 / std::max(1, requestSettings.fpsRange->minFps)));
  }
  return std::chrono::nanoseconds(
      static_cast<uint64_t>(1e9 / VirtualCameraDevice::kMinFps));
}

}  // namespace

CaptureRequestBuffer::CaptureRequestBuffer(int streamId, int bufferId,
@@ -419,7 +429,7 @@ void VirtualCameraRenderThread::processCaptureRequest(
  std::chrono::nanoseconds timestamp =
      std::chrono::duration_cast<std::chrono::nanoseconds>(
          std::chrono::steady_clock::now().time_since_epoch());
  std::chrono::nanoseconds lastAcquisitionTimestamp(
  const std::chrono::nanoseconds lastAcquisitionTimestamp(
      mLastAcquisitionTimestampNanoseconds.exchange(timestamp.count(),
                                                    std::memory_order_relaxed));

@@ -449,6 +459,29 @@ void VirtualCameraRenderThread::processCaptureRequest(
    }
  }

  // Calculate the maximal amount of time we can afford to wait for next frame.
  const std::chrono::nanoseconds maxFrameDuration =
      getMaxFrameDuration(request.getRequestSettings());
  const std::chrono::nanoseconds elapsedDuration =
      timestamp - lastAcquisitionTimestamp;
  if (elapsedDuration < maxFrameDuration) {
    // We can afford to wait for next frame.
    // Note that if there's already new frame in the input Surface, the call
    // below returns immediatelly.
    bool gotNewFrame = mEglSurfaceTexture->waitForNextFrame(maxFrameDuration -
                                                            elapsedDuration);
    timestamp = std::chrono::duration_cast<std::chrono::nanoseconds>(
        std::chrono::steady_clock::now().time_since_epoch());
    if (!gotNewFrame) {
      ALOGV(
          "%s: No new frame received on input surface after waiting for "
          "%" PRIu64 "ns, repeating last frame.",
          __func__,
          static_cast<uint64_t>((timestamp - lastAcquisitionTimestamp).count()));
    }
    mLastAcquisitionTimestampNanoseconds.store(timestamp.count(),
                                               std::memory_order_relaxed);
  }
  // Acquire new (most recent) image from the Surface.
  mEglSurfaceTexture->updateTexture();

+6 −0
Original line number Diff line number Diff line
@@ -15,6 +15,7 @@
 */

// #define LOG_NDEBUG 0
#include "utils/Timers.h"
#define LOG_TAG "EglSurfaceTexture"

#include <cstdint>
@@ -63,6 +64,11 @@ sp<GraphicBuffer> EglSurfaceTexture::getCurrentBuffer() {
  return mGlConsumer->getCurrentBuffer();
}

bool EglSurfaceTexture::waitForNextFrame(const std::chrono::nanoseconds timeout) {
  return mSurface->waitForNextFrame(mGlConsumer->getFrameNumber(),
                                    static_cast<nsecs_t>(timeout.count()));
}

GLuint EglSurfaceTexture::updateTexture() {
  mGlConsumer->updateTexImage();
  return mTextureId;
+7 −0
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@
#ifndef ANDROID_COMPANION_VIRTUALCAMERA_EGLSURFACETEXTURE_H
#define ANDROID_COMPANION_VIRTUALCAMERA_EGLSURFACETEXTURE_H

#include <chrono>
#include <cstdint>

#include "GLES/gl.h"
@@ -51,6 +52,12 @@ class EglSurfaceTexture {
  // Get height of surface / texture.
  uint32_t getHeight() const;

  // Wait for next frame to be available in the surface
  // until timeout.
  //
  // Returns false on timeout, true if new frame was received before timeout.
  bool waitForNextFrame(std::chrono::nanoseconds timeout);

  // Update the texture with the most recent submitted buffer.
  // Most be called on thread with EGL context.
  //