Loading services/camera/virtualcamera/Android.bp +12 −11 Original line number Diff line number Diff line Loading @@ -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", Loading @@ -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", Loading services/camera/virtualcamera/VirtualCameraRenderThread.cc +34 −14 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ // #define LOG_NDEBUG 0 #define LOG_TAG "VirtualCameraRenderThread" #include "VirtualCameraRenderThread.h" #include <android_companion_virtualdevice_flags.h> Loading Loading @@ -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; Loading Loading @@ -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 Loading Loading @@ -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. Loading Loading @@ -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. Loading @@ -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. Loading @@ -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()) { Loading @@ -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 = Loading @@ -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( Loading Loading @@ -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>( Loading services/camera/virtualcamera/VirtualCameraSession.cc +2 −2 Original line number Diff line number Diff line Loading @@ -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); Loading Loading @@ -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; Loading services/camera/virtualcamera/util/EglSurfaceTexture.cc +45 −26 Original line number Diff line number Diff line Loading @@ -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> Loading @@ -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 { Loading @@ -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) { Loading Loading @@ -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() { Loading @@ -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() { Loading @@ -126,7 +145,7 @@ std::chrono::nanoseconds EglSurfaceTexture::getTimestamp() { } bool EglSurfaceTexture::isFirstFrameDrawn() { return mIsFirstFrameDrawn.load(); return mGlConsumer->getFrameNumber() > 0; } GLuint EglSurfaceTexture::updateTexture() { Loading services/camera/virtualcamera/util/EglSurfaceTexture.h +20 −1 Original line number Diff line number Diff line Loading @@ -22,7 +22,9 @@ #include <gui/Surface.h> #include <utils/RefBase.h> #include <atomic> #include <chrono> #include <condition_variable> #include <cstdint> namespace android { Loading Loading @@ -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; Loading @@ -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 Loading Loading
services/camera/virtualcamera/Android.bp +12 −11 Original line number Diff line number Diff line Loading @@ -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", Loading @@ -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", Loading
services/camera/virtualcamera/VirtualCameraRenderThread.cc +34 −14 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ // #define LOG_NDEBUG 0 #define LOG_TAG "VirtualCameraRenderThread" #include "VirtualCameraRenderThread.h" #include <android_companion_virtualdevice_flags.h> Loading Loading @@ -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; Loading Loading @@ -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 Loading Loading @@ -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. Loading Loading @@ -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. Loading @@ -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. Loading @@ -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()) { Loading @@ -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 = Loading @@ -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( Loading Loading @@ -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>( Loading
services/camera/virtualcamera/VirtualCameraSession.cc +2 −2 Original line number Diff line number Diff line Loading @@ -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); Loading Loading @@ -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; Loading
services/camera/virtualcamera/util/EglSurfaceTexture.cc +45 −26 Original line number Diff line number Diff line Loading @@ -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> Loading @@ -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 { Loading @@ -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) { Loading Loading @@ -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() { Loading @@ -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() { Loading @@ -126,7 +145,7 @@ std::chrono::nanoseconds EglSurfaceTexture::getTimestamp() { } bool EglSurfaceTexture::isFirstFrameDrawn() { return mIsFirstFrameDrawn.load(); return mGlConsumer->getFrameNumber() > 0; } GLuint EglSurfaceTexture::updateTexture() { Loading
services/camera/virtualcamera/util/EglSurfaceTexture.h +20 −1 Original line number Diff line number Diff line Loading @@ -22,7 +22,9 @@ #include <gui/Surface.h> #include <utils/RefBase.h> #include <atomic> #include <chrono> #include <condition_variable> #include <cstdint> namespace android { Loading Loading @@ -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; Loading @@ -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 Loading