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

Commit e4468b54 authored by Treehugger Robot's avatar Treehugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Fix waitForNextFrame method" into main

parents cd76e793 0429eb8d
Loading
Loading
Loading
Loading
+12 −11
Original line number Diff line number Diff line
@@ -7,29 +7,29 @@ package {
cc_defaults {
    name: "libvirtualcamera_defaults",
    shared_libs: [
        "android.companion.virtualdevice.flags-aconfig-cc",
        "android.hardware.common-V2-ndk",
        "android.hardware.common.fmq-V1-ndk",
        "libEGL",
        "libGLESv2",
        "libGLESv3",
        "libbase",
        "libbinder",
        "libbinder_ndk",
        "libcamera_metadata",
        "libcutils",
        "libexif",
        "liblog",
        "libfmq",
        "libgui",
        "libjpeg",
        "liblog",
        "libnativewindow",
        "libbase",
        "libcutils",
        "libui",
        "libutils",
        "libEGL",
        "libGLESv2",
        "libGLESv3",
        "android.companion.virtualdevice.flags-aconfig-cc",
    ],
    static_libs: [
        "android.hardware.camera.common@1.0-helper",
        "android.hardware.camera.common-V1-ndk",
        "android.hardware.camera.common@1.0-helper",
        "android.hardware.camera.device-V2-ndk",
        "android.hardware.camera.metadata-V2-ndk",
        "android.hardware.camera.provider-V2-ndk",
@@ -43,20 +43,21 @@ cc_defaults {
        "-Wformat",
        "-Wthread-safety",
    ],
    cpp_std: "c++20",
}

cc_library_static {
    name: "libvirtualcamera_utils",
    srcs: [
        "util/JpegUtil.cc",
        "util/MetadataUtil.cc",
        "util/Util.cc",
        "util/EglDisplayContext.cc",
        "util/EglFramebuffer.cc",
        "util/EglProgram.cc",
        "util/EglSurfaceTexture.cc",
        "util/EglUtil.cc",
        "util/JpegUtil.cc",
        "util/MetadataUtil.cc",
        "util/Permissions.cc",
        "util/Util.cc",
    ],
    defaults: [
        "libvirtualcamera_defaults",
+34 −14
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@

// #define LOG_NDEBUG 0
#define LOG_TAG "VirtualCameraRenderThread"

#include "VirtualCameraRenderThread.h"

#include <android_companion_virtualdevice_flags.h>
@@ -103,6 +104,8 @@ static constexpr UpdateTextureTask kUpdateTextureTask;
// The number of nanosecond to wait for the first frame to be drawn on the input surface
static constexpr std::chrono::nanoseconds kMaxWaitFirstFrame = 3s;

static constexpr double kOneSecondInNanos = 1e9;

NotifyMsg createShutterNotifyMsg(int frameNumber,
                                 std::chrono::nanoseconds timestamp) {
  NotifyMsg msg;
@@ -217,10 +220,17 @@ 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)));
        kOneSecondInNanos / std::max(1, requestSettings.fpsRange->minFps)));
  }
  return std::chrono::nanoseconds(
      static_cast<uint64_t>(1e9 / VirtualCameraDevice::kMinFps));
      static_cast<uint64_t>(kOneSecondInNanos / VirtualCameraDevice::kMinFps));
}

// Translate a frame duration into a fps value with triple decimal precision
double nanosToFps(std::chrono::nanoseconds frameDuration) {
  const double oneSecondInNanos = 1e9;
  const double fpsNanos = oneSecondInNanos / frameDuration.count();
  return fpsNanos;
}

}  // namespace
@@ -283,6 +293,7 @@ const RequestSettings& ProcessCaptureRequestTask::getRequestSettings() const {

void VirtualCameraRenderThread::requestTextureUpdate() {
  std::lock_guard<std::mutex> lock(mLock);
  ALOGV("%s", __func__);
  // If queue is not empty, we don't need to set the mTextureUpdateRequested
  // flag, since the texture will be updated during ProcessCaptureRequestTask
  // processing anyway.
@@ -396,16 +407,20 @@ void VirtualCameraRenderThread::threadLoop() {

void VirtualCameraRenderThread::processTask(
    const ProcessCaptureRequestTask& request) {
  std::chrono::nanoseconds timestamp =
  ALOGV("%s request frame number %d", __func__, request.getFrameNumber());
  std::chrono::nanoseconds deviceTime =
      std::chrono::duration_cast<std::chrono::nanoseconds>(
          std::chrono::steady_clock::now().time_since_epoch());
  const std::chrono::nanoseconds lastAcquisitionTimestamp(
      mLastAcquisitionTimestampNanoseconds.exchange(timestamp.count(),
      mLastAcquisitionTimestampNanoseconds.exchange(deviceTime.count(),
                                                    std::memory_order_relaxed));

  if (request.getRequestSettings().fpsRange) {
    ALOGV("%s request fps {%d,%d}", __func__,
          request.getRequestSettings().fpsRange->minFps,
          request.getRequestSettings().fpsRange->maxFps);
    int maxFps = std::max(1, request.getRequestSettings().fpsRange->maxFps);
    timestamp = throttleRendering(maxFps, lastAcquisitionTimestamp, timestamp);
    deviceTime = throttleRendering(maxFps, lastAcquisitionTimestamp, deviceTime);
  }

  // Calculate the maximal amount of time we can afford to wait for next frame.
@@ -416,7 +431,7 @@ void VirtualCameraRenderThread::processTask(
      isFirstFrameDrawn ? getMaxFrameDuration(request.getRequestSettings())
                        : kMaxWaitFirstFrame;
  const std::chrono::nanoseconds elapsedDuration =
      isFirstFrameDrawn ? timestamp - lastAcquisitionTimestamp : 0ns;
      isFirstFrameDrawn ? deviceTime - lastAcquisitionTimestamp : 0ns;

  if (elapsedDuration < maxFrameDuration) {
    // We can afford to wait for next frame.
@@ -424,7 +439,7 @@ void VirtualCameraRenderThread::processTask(
    // below returns immediatelly.
    bool gotNewFrame = mEglSurfaceTexture->waitForNextFrame(maxFrameDuration -
                                                            elapsedDuration);
    timestamp = std::chrono::duration_cast<std::chrono::nanoseconds>(
    deviceTime = std::chrono::duration_cast<std::chrono::nanoseconds>(
        std::chrono::steady_clock::now().time_since_epoch());
    if (!gotNewFrame) {
      if (!mEglSurfaceTexture->isFirstFrameDrawn()) {
@@ -442,14 +457,15 @@ void VirtualCameraRenderThread::processTask(
          "%s: No new frame received on input surface after waiting for "
          "%" PRIu64 "ns, repeating last frame.",
          __func__,
          static_cast<uint64_t>((timestamp - lastAcquisitionTimestamp).count()));
          static_cast<uint64_t>(
              (deviceTime - lastAcquisitionTimestamp).count()));
    }
    mLastAcquisitionTimestampNanoseconds.store(timestamp.count(),
    mLastAcquisitionTimestampNanoseconds.store(deviceTime.count(),
                                               std::memory_order_relaxed);
  }
  // Acquire new (most recent) image from the Surface.
  mEglSurfaceTexture->updateTexture();
  std::chrono::nanoseconds captureTimestamp = timestamp;
  std::chrono::nanoseconds captureTimestamp = deviceTime;

  if (flags::camera_timestamp_from_surface()) {
    std::chrono::nanoseconds surfaceTimestamp =
@@ -457,8 +473,11 @@ void VirtualCameraRenderThread::processTask(
    if (surfaceTimestamp.count() > 0) {
      captureTimestamp = surfaceTimestamp;
    }
    ALOGV("%s captureTimestamp:%lld timestamp:%lld", __func__,
          captureTimestamp.count(), timestamp.count());
    ALOGV(
        "%s surfaceTimestamp:%lld deviceTime:%lld captureTimestamp:%lld "
        "(nanos)",
        __func__, surfaceTimestamp.count(), deviceTime.count(),
        captureTimestamp.count());
  }

  std::unique_ptr<CaptureResult> captureResult = createCaptureResult(
@@ -488,11 +507,12 @@ std::chrono::nanoseconds VirtualCameraRenderThread::throttleRendering(
    // We're too fast for the configured maxFps, let's wait a bit.
    const std::chrono::nanoseconds sleepTime = minFrameDuration - frameDuration;
    ALOGV("Current frame duration would  be %" PRIu64
          " ns corresponding to, "
          " ns corresponding to %.3f Fps, "
          "sleeping for %" PRIu64
          " ns before updating texture to match maxFps %d",
          static_cast<uint64_t>(frameDuration.count()),
          static_cast<uint64_t>(sleepTime.count()), maxFps);
          nanosToFps(frameDuration), static_cast<uint64_t>(sleepTime.count()),
          maxFps);

    std::this_thread::sleep_for(sleepTime);
    timestamp = std::chrono::duration_cast<std::chrono::nanoseconds>(
+2 −2
Original line number Diff line number Diff line
@@ -518,7 +518,7 @@ ndk::ScopedAStatus VirtualCameraSession::isReconfigurationRequired(
ndk::ScopedAStatus VirtualCameraSession::processCaptureRequest(
    const std::vector<CaptureRequest>& in_requests,
    const std::vector<BufferCache>& in_cachesToRemove, int32_t* _aidl_return) {
  ALOGV("%s", __func__);
  ALOGV("%s: request count: %zu", __func__, in_requests.size());

  if (!in_cachesToRemove.empty()) {
    mSessionContext.removeBufferCaches(in_cachesToRemove);
@@ -575,7 +575,7 @@ std::set<int> VirtualCameraSession::getStreamIds() const {

ndk::ScopedAStatus VirtualCameraSession::processCaptureRequest(
    const CaptureRequest& request) {
  ALOGV("%s: request: %s", __func__, request.toString().c_str());
  ALOGV("%s: CaptureRequest { frameNumber:%d }", __func__, request.frameNumber);

  std::shared_ptr<ICameraDeviceCallback> cameraCallback = nullptr;
  RequestSettings requestSettings;
+45 −26
Original line number Diff line number Diff line
@@ -15,11 +15,10 @@
 */

// #define LOG_NDEBUG 0
#include <chrono>

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

#include "EglSurfaceTexture.h"

#include <GLES/gl.h>
#include <com_android_graphics_libgui_flags.h>
#include <gui/BufferQueue.h>
@@ -27,9 +26,10 @@
#include <gui/IGraphicBufferProducer.h>
#include <hardware/gralloc.h>

#include <chrono>
#include <cstdint>
#include <mutex>

#include "EglSurfaceTexture.h"
#include "EglUtil.h"

namespace android {
@@ -40,22 +40,27 @@ namespace {
// Maximal number of buffers producer can dequeue without blocking.
constexpr int kBufferProducerMaxDequeueBufferCount = 64;

class FrameAvailableListenerProxy : public ConsumerBase::FrameAvailableListener {
 public:
  FrameAvailableListenerProxy(const std::function<void()>& callback)
      : mOnFrameAvailableCallback(callback) {
  }
}  // namespace

  virtual void onFrameAvailable(const BufferItem&) override {
    ALOGV("%s: onFrameAvailable", __func__);
    mOnFrameAvailableCallback();
EglSurfaceTexture::FrameAvailableListenerProxy::FrameAvailableListenerProxy(
    EglSurfaceTexture* surface)
    : mSurface(*surface) {
}

 private:
  std::function<void()> mOnFrameAvailableCallback;
};
void EglSurfaceTexture::FrameAvailableListenerProxy::setCallback(
    const std::function<void()>& callback) {
  mOnFrameAvailableCallback = callback;
}

}  // namespace
void EglSurfaceTexture::FrameAvailableListenerProxy::onFrameAvailable(
    const BufferItem&) {
  long frameNumber = mSurface.mGlConsumer->getFrameNumber();
  ALOGV("%s: onFrameAvailable frameNumber %ld", __func__, frameNumber);
  mSurface.mFrameAvailableCondition.notify_all();
  if (mOnFrameAvailableCallback) {
    mOnFrameAvailableCallback();
  }
}

EglSurfaceTexture::EglSurfaceTexture(const uint32_t width, const uint32_t height)
    : mWidth(width), mHeight(height) {
@@ -90,6 +95,8 @@ EglSurfaceTexture::EglSurfaceTexture(const uint32_t width, const uint32_t height

  mSurface = sp<Surface>::make(mBufferProducer);
#endif  // COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ)
  mFrameAvailableListenerProxy = sp<FrameAvailableListenerProxy>::make(this);
  mGlConsumer->setFrameAvailableListener(mFrameAvailableListenerProxy);
}

EglSurfaceTexture::~EglSurfaceTexture() {
@@ -108,17 +115,29 @@ sp<GraphicBuffer> EglSurfaceTexture::getCurrentBuffer() {

void EglSurfaceTexture::setFrameAvailableListener(
    const std::function<void()>& listener) {
  mFrameAvailableListener =
      sp<FrameAvailableListenerProxy>::make([this, listener]() {
        mIsFirstFrameDrawn.store(true);
        listener();
      });
  mGlConsumer->setFrameAvailableListener(mFrameAvailableListener);
  mFrameAvailableListenerProxy->setCallback(listener);
}

bool EglSurfaceTexture::waitForNextFrame(const std::chrono::nanoseconds timeout) {
  return mSurface->waitForNextFrame(mGlConsumer->getFrameNumber(),
                                    static_cast<nsecs_t>(timeout.count()));
  std::unique_lock<std::mutex> lock(mWaitForFrameMutex);
  mGlConsumer->updateTexImage();
  const long lastRenderedFrame = mGlConsumer->getFrameNumber();
  const long lastWaitedForFrame = mLastWaitedFrame.exchange(lastRenderedFrame);
  ALOGV("%s lastRenderedFrame:%ld lastWaitedForFrame: %ld", __func__,
        lastRenderedFrame, lastWaitedForFrame);
  if (lastRenderedFrame > lastWaitedForFrame) {
    return true;
  }
  ALOGV(
      "%s waiting for max %lld ns. Last waited frame:%ld, last rendered "
      "frame:%ld",
      __func__, timeout.count(), lastWaitedForFrame, lastRenderedFrame);
  return mFrameAvailableCondition.wait_for(lock, timeout, [this]() {
    // Call updateTexImage to update the frame number.
    mGlConsumer->updateTexImage();
    const long lastRenderedFrame = mGlConsumer->getFrameNumber();
    return lastRenderedFrame > mLastWaitedFrame.exchange(lastRenderedFrame);
  });
}

std::chrono::nanoseconds EglSurfaceTexture::getTimestamp() {
@@ -126,7 +145,7 @@ std::chrono::nanoseconds EglSurfaceTexture::getTimestamp() {
}

bool EglSurfaceTexture::isFirstFrameDrawn() {
  return mIsFirstFrameDrawn.load();
  return mGlConsumer->getFrameNumber() > 0;
}

GLuint EglSurfaceTexture::updateTexture() {
+20 −1
Original line number Diff line number Diff line
@@ -22,7 +22,9 @@
#include <gui/Surface.h>
#include <utils/RefBase.h>

#include <atomic>
#include <chrono>
#include <condition_variable>
#include <cstdint>

namespace android {
@@ -88,6 +90,20 @@ class EglSurfaceTexture {
  // Returns true is a frame has ever been drawn on this surface.
  bool isFirstFrameDrawn();

  class FrameAvailableListenerProxy
      : public ConsumerBase::FrameAvailableListener {
   public:
    FrameAvailableListenerProxy(EglSurfaceTexture* surface);

    void setCallback(const std::function<void()>& callback);

    virtual void onFrameAvailable(const BufferItem&) override;

   private:
    EglSurfaceTexture& mSurface;
    std::function<void()> mOnFrameAvailableCallback;
  };

 private:
#if !COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ)
  sp<IGraphicBufferProducer> mBufferProducer;
@@ -98,8 +114,11 @@ class EglSurfaceTexture {
  GLuint mTextureId;
  const uint32_t mWidth;
  const uint32_t mHeight;
  std::atomic_bool mIsFirstFrameDrawn = false;
  std::atomic_long mLastWaitedFrame = 0;
  sp<FrameAvailableListenerProxy> mFrameAvailableListenerProxy;
  sp<ConsumerBase::FrameAvailableListener> mFrameAvailableListener;
  std::condition_variable mFrameAvailableCondition;
  std::mutex mWaitForFrameMutex;
};

}  // namespace virtualcamera