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

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

Merge changes Ib0372931,I8ec56adf into main

* changes:
  Use timestamp instead of frame number when generating test pattern.
  Reconfigure the input surface when needed.
parents ef6307ab 58a7ac4c
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -618,6 +618,10 @@ Resolution VirtualCameraDevice::getMaxInputResolution() const {
  return maxResolution.value();
}

int VirtualCameraDevice::allocateInputStreamId() {
  return mNextInputStreamId++;
}

std::shared_ptr<VirtualCameraDevice> VirtualCameraDevice::sharedFromThis() {
  // SharedRefBase which BnCameraDevice inherits from breaks
  // std::enable_shared_from_this. This is recommended replacement for
+5 −0
Original line number Diff line number Diff line
@@ -104,6 +104,9 @@ class VirtualCameraDevice
  // Returns largest supported input resolution.
  Resolution getMaxInputResolution() const;

  // Allocate and return next id for input stream (input surface).
  int allocateInputStreamId();

  // Maximal number of RAW streams - virtual camera doesn't support RAW streams.
  static constexpr int32_t kMaxNumberOfRawStreams = 0;

@@ -148,6 +151,8 @@ class VirtualCameraDevice
  const std::vector<
      aidl::android::companion::virtualcamera::SupportedStreamConfiguration>
      mSupportedInputConfigurations;

  std::atomic_int mNextInputStreamId;
};

}  // namespace virtualcamera
+73 −13
Original line number Diff line number Diff line
@@ -212,6 +212,27 @@ Resolution resolutionFromInputConfig(
  return Resolution(inputConfig.width, inputConfig.height);
}

std::optional<Resolution> resolutionFromSurface(const sp<Surface> surface) {
  Resolution res{0, 0};
  if (surface == nullptr) {
    ALOGE("%s: Cannot get resolution from null surface", __func__);
    return std::nullopt;
  }

  int status = surface->query(NATIVE_WINDOW_WIDTH, &res.width);
  if (status != NO_ERROR) {
    ALOGE("%s: Failed to get width from surface", __func__);
    return std::nullopt;
  }

  status = surface->query(NATIVE_WINDOW_HEIGHT, &res.height);
  if (status != NO_ERROR) {
    ALOGE("%s: Failed to get height from surface", __func__);
    return std::nullopt;
  }
  return res;
}

std::optional<SupportedStreamConfiguration> pickInputConfigurationForStreams(
    const std::vector<Stream>& requestedStreams,
    const std::vector<SupportedStreamConfiguration>& supportedInputConfigs) {
@@ -292,13 +313,13 @@ VirtualCameraSession::VirtualCameraSession(

ndk::ScopedAStatus VirtualCameraSession::close() {
  ALOGV("%s", __func__);
  {
    std::lock_guard<std::mutex> lock(mLock);

    if (mVirtualCameraClientCallback != nullptr) {
    mVirtualCameraClientCallback->onStreamClosed(/*streamId=*/0);
      mVirtualCameraClientCallback->onStreamClosed(mCurrentInputStreamId);
    }

  {
    std::lock_guard<std::mutex> lock(mLock);
    if (mRenderThread != nullptr) {
      mRenderThread->stop();
      mRenderThread = nullptr;
@@ -339,6 +360,7 @@ ndk::ScopedAStatus VirtualCameraSession::configureStreams(
  }

  sp<Surface> inputSurface = nullptr;
  int inputStreamId = -1;
  std::optional<SupportedStreamConfiguration> inputConfig;
  {
    std::lock_guard<std::mutex> lock(mLock);
@@ -358,13 +380,49 @@ ndk::ScopedAStatus VirtualCameraSession::configureStreams(
          __func__, in_requestedConfiguration.toString().c_str());
      return cameraStatus(Status::ILLEGAL_ARGUMENT);
    }
    if (mRenderThread == nullptr) {

    if (mRenderThread != nullptr) {
      // If there's already a render thread, it means this is not a first
      // configuration call. If the surface has the same resolution and pixel
      // format as the picked config, we don't need to do anything, the current
      // render thread is capable of serving new set of configuration. However
      // if it differens, we need to discard the current surface and
      // reinitialize the render thread.

      std::optional<Resolution> currentInputResolution =
          resolutionFromSurface(mRenderThread->getInputSurface());
      if (currentInputResolution.has_value() &&
          *currentInputResolution == resolutionFromInputConfig(*inputConfig)) {
        ALOGI(
            "%s: Newly configured set of streams matches existing client "
            "surface (%dx%d)",
            __func__, currentInputResolution->width,
            currentInputResolution->height);
        return ndk::ScopedAStatus::ok();
      }

      if (mVirtualCameraClientCallback != nullptr) {
        mVirtualCameraClientCallback->onStreamClosed(mCurrentInputStreamId);
      }

      ALOGV(
          "%s: Newly requested output streams are not suitable for "
          "pre-existing surface (%dx%d), creating new surface (%dx%d)",
          __func__, currentInputResolution->width,
          currentInputResolution->height, inputConfig->width,
          inputConfig->height);

      mRenderThread->flush();
      mRenderThread->stop();
    }

    mRenderThread = std::make_unique<VirtualCameraRenderThread>(
        mSessionContext, resolutionFromInputConfig(*inputConfig),
        virtualCamera->getMaxInputResolution(), mCameraDeviceCallback);
    mRenderThread->start();
    inputSurface = mRenderThread->getInputSurface();
    }
    inputStreamId = mCurrentInputStreamId =
        virtualCamera->allocateInputStreamId();
  }

  if (mVirtualCameraClientCallback != nullptr && inputSurface != nullptr) {
@@ -372,7 +430,7 @@ ndk::ScopedAStatus VirtualCameraSession::configureStreams(
    // support for multiple input streams is implemented. For now we always
    // create single texture.
    mVirtualCameraClientCallback->onStreamConfigured(
        /*streamId=*/0, aidl::android::view::Surface(inputSurface.get()),
        inputStreamId, aidl::android::view::Surface(inputSurface.get()),
        inputConfig->width, inputConfig->height, inputConfig->pixelFormat);
  }

@@ -519,6 +577,7 @@ ndk::ScopedAStatus VirtualCameraSession::processCaptureRequest(

  std::shared_ptr<ICameraDeviceCallback> cameraCallback = nullptr;
  RequestSettings requestSettings;
  int currentInputStreamId;
  {
    std::lock_guard<std::mutex> lock(mLock);

@@ -537,6 +596,7 @@ ndk::ScopedAStatus VirtualCameraSession::processCaptureRequest(
    requestSettings = createSettingsFromMetadata(mCurrentRequestMetadata);

    cameraCallback = mCameraDeviceCallback;
    currentInputStreamId = mCurrentInputStreamId;
  }

  if (cameraCallback == nullptr) {
@@ -574,7 +634,7 @@ ndk::ScopedAStatus VirtualCameraSession::processCaptureRequest(

  if (mVirtualCameraClientCallback != nullptr) {
    auto status = mVirtualCameraClientCallback->onProcessCaptureRequest(
        /*streamId=*/0, request.frameNumber);
        currentInputStreamId, request.frameNumber);
    if (!status.isOk()) {
      ALOGE(
          "Failed to invoke onProcessCaptureRequest client callback for frame "
+2 −0
Original line number Diff line number Diff line
@@ -143,6 +143,8 @@ class VirtualCameraSession
      GUARDED_BY(mLock);

  std::unique_ptr<VirtualCameraRenderThread> mRenderThread GUARDED_BY(mLock);

  int mCurrentInputStreamId GUARDED_BY(mLock);
};

}  // namespace virtualcamera
+1 −1
Original line number Diff line number Diff line
@@ -107,7 +107,7 @@ void TestPatternRenderer::renderThreadLoop(
    }

    // Render the test pattern and update timestamp.
    testPatternProgram.draw(frameNumber++);
    testPatternProgram.draw(ts);
    eglDisplayContext.swapBuffers();
    lastFrameTs = getCurrentTimestamp();
  }
Loading