xref: /aosp_15_r20/frameworks/av/services/camera/virtualcamera/VirtualCameraTestInstance.cc (revision ec779b8e0859a360c3d303172224686826e6e0e1)
1*ec779b8eSAndroid Build Coastguard Worker /*
2*ec779b8eSAndroid Build Coastguard Worker  * Copyright (C) 2024 The Android Open Source Project
3*ec779b8eSAndroid Build Coastguard Worker  *
4*ec779b8eSAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*ec779b8eSAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*ec779b8eSAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*ec779b8eSAndroid Build Coastguard Worker  *
8*ec779b8eSAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*ec779b8eSAndroid Build Coastguard Worker  *
10*ec779b8eSAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*ec779b8eSAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*ec779b8eSAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*ec779b8eSAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*ec779b8eSAndroid Build Coastguard Worker  * limitations under the License.
15*ec779b8eSAndroid Build Coastguard Worker  */
16*ec779b8eSAndroid Build Coastguard Worker 
17*ec779b8eSAndroid Build Coastguard Worker // #define LOG_NDEBUG 0
18*ec779b8eSAndroid Build Coastguard Worker #define LOG_TAG "VirtualCameraTestInstance"
19*ec779b8eSAndroid Build Coastguard Worker 
20*ec779b8eSAndroid Build Coastguard Worker #include "VirtualCameraTestInstance.h"
21*ec779b8eSAndroid Build Coastguard Worker 
22*ec779b8eSAndroid Build Coastguard Worker #include <atomic>
23*ec779b8eSAndroid Build Coastguard Worker #include <chrono>
24*ec779b8eSAndroid Build Coastguard Worker #include <memory>
25*ec779b8eSAndroid Build Coastguard Worker #include <mutex>
26*ec779b8eSAndroid Build Coastguard Worker #include <ratio>
27*ec779b8eSAndroid Build Coastguard Worker #include <thread>
28*ec779b8eSAndroid Build Coastguard Worker 
29*ec779b8eSAndroid Build Coastguard Worker #include "GLES/gl.h"
30*ec779b8eSAndroid Build Coastguard Worker #include "android/binder_auto_utils.h"
31*ec779b8eSAndroid Build Coastguard Worker #include "android/native_window.h"
32*ec779b8eSAndroid Build Coastguard Worker #include "log/log.h"
33*ec779b8eSAndroid Build Coastguard Worker #include "util/EglDisplayContext.h"
34*ec779b8eSAndroid Build Coastguard Worker #include "util/EglProgram.h"
35*ec779b8eSAndroid Build Coastguard Worker 
36*ec779b8eSAndroid Build Coastguard Worker namespace android {
37*ec779b8eSAndroid Build Coastguard Worker namespace companion {
38*ec779b8eSAndroid Build Coastguard Worker namespace virtualcamera {
39*ec779b8eSAndroid Build Coastguard Worker 
40*ec779b8eSAndroid Build Coastguard Worker using ::aidl::android::companion::virtualcamera::Format;
41*ec779b8eSAndroid Build Coastguard Worker using ::aidl::android::view::Surface;
42*ec779b8eSAndroid Build Coastguard Worker using ::ndk::ScopedAStatus;
43*ec779b8eSAndroid Build Coastguard Worker 
44*ec779b8eSAndroid Build Coastguard Worker namespace {
45*ec779b8eSAndroid Build Coastguard Worker 
nativeWindowFromSurface(const Surface & surface)46*ec779b8eSAndroid Build Coastguard Worker std::shared_ptr<ANativeWindow> nativeWindowFromSurface(const Surface& surface) {
47*ec779b8eSAndroid Build Coastguard Worker   ANativeWindow* nativeWindow = surface.get();
48*ec779b8eSAndroid Build Coastguard Worker   if (nativeWindow != nullptr) {
49*ec779b8eSAndroid Build Coastguard Worker     ANativeWindow_acquire(nativeWindow);
50*ec779b8eSAndroid Build Coastguard Worker   }
51*ec779b8eSAndroid Build Coastguard Worker   return std::shared_ptr<ANativeWindow>(nativeWindow, ANativeWindow_release);
52*ec779b8eSAndroid Build Coastguard Worker }
53*ec779b8eSAndroid Build Coastguard Worker 
getCurrentTimestamp()54*ec779b8eSAndroid Build Coastguard Worker std::chrono::nanoseconds getCurrentTimestamp() {
55*ec779b8eSAndroid Build Coastguard Worker   return std::chrono::duration_cast<std::chrono::nanoseconds>(
56*ec779b8eSAndroid Build Coastguard Worker       std::chrono::steady_clock::now().time_since_epoch());
57*ec779b8eSAndroid Build Coastguard Worker }
58*ec779b8eSAndroid Build Coastguard Worker 
59*ec779b8eSAndroid Build Coastguard Worker }  // namespace
60*ec779b8eSAndroid Build Coastguard Worker 
TestPatternRenderer(std::shared_ptr<ANativeWindow> nativeWindow,int fps)61*ec779b8eSAndroid Build Coastguard Worker TestPatternRenderer::TestPatternRenderer(
62*ec779b8eSAndroid Build Coastguard Worker     std::shared_ptr<ANativeWindow> nativeWindow, int fps)
63*ec779b8eSAndroid Build Coastguard Worker     : mFps(fps), mNativeWindow(nativeWindow) {
64*ec779b8eSAndroid Build Coastguard Worker }
65*ec779b8eSAndroid Build Coastguard Worker 
start()66*ec779b8eSAndroid Build Coastguard Worker void TestPatternRenderer::start() {
67*ec779b8eSAndroid Build Coastguard Worker   std::lock_guard<std::mutex> lock(mLock);
68*ec779b8eSAndroid Build Coastguard Worker   if (mRunning.exchange(true, std::memory_order_relaxed)) {
69*ec779b8eSAndroid Build Coastguard Worker     ALOGW("Render thread already started.");
70*ec779b8eSAndroid Build Coastguard Worker     return;
71*ec779b8eSAndroid Build Coastguard Worker   }
72*ec779b8eSAndroid Build Coastguard Worker   mThread =
73*ec779b8eSAndroid Build Coastguard Worker       std::thread(&TestPatternRenderer::renderThreadLoop, this, mNativeWindow);
74*ec779b8eSAndroid Build Coastguard Worker }
75*ec779b8eSAndroid Build Coastguard Worker 
stop()76*ec779b8eSAndroid Build Coastguard Worker void TestPatternRenderer::stop() {
77*ec779b8eSAndroid Build Coastguard Worker   std::lock_guard<std::mutex> lock(mLock);
78*ec779b8eSAndroid Build Coastguard Worker   if (!mRunning.exchange(false, std::memory_order_relaxed)) {
79*ec779b8eSAndroid Build Coastguard Worker     ALOGW("Render thread already stopped.");
80*ec779b8eSAndroid Build Coastguard Worker     return;
81*ec779b8eSAndroid Build Coastguard Worker   }
82*ec779b8eSAndroid Build Coastguard Worker   mThread.detach();
83*ec779b8eSAndroid Build Coastguard Worker   mRunning = false;
84*ec779b8eSAndroid Build Coastguard Worker }
85*ec779b8eSAndroid Build Coastguard Worker 
renderThreadLoop(std::shared_ptr<ANativeWindow> nativeWindow)86*ec779b8eSAndroid Build Coastguard Worker void TestPatternRenderer::renderThreadLoop(
87*ec779b8eSAndroid Build Coastguard Worker     std::shared_ptr<ANativeWindow> nativeWindow) {
88*ec779b8eSAndroid Build Coastguard Worker   // Prevent destruction of this instance until the thread terminates.
89*ec779b8eSAndroid Build Coastguard Worker   std::shared_ptr<TestPatternRenderer> thiz = shared_from_this();
90*ec779b8eSAndroid Build Coastguard Worker 
91*ec779b8eSAndroid Build Coastguard Worker   ALOGV("Starting test client render loop");
92*ec779b8eSAndroid Build Coastguard Worker 
93*ec779b8eSAndroid Build Coastguard Worker   EglDisplayContext eglDisplayContext(nativeWindow);
94*ec779b8eSAndroid Build Coastguard Worker   EglTestPatternProgram testPatternProgram;
95*ec779b8eSAndroid Build Coastguard Worker 
96*ec779b8eSAndroid Build Coastguard Worker   const std::chrono::nanoseconds frameDuration(
97*ec779b8eSAndroid Build Coastguard Worker       static_cast<uint64_t>(1e9 / mFps));
98*ec779b8eSAndroid Build Coastguard Worker 
99*ec779b8eSAndroid Build Coastguard Worker   std::chrono::nanoseconds lastFrameTs(0);
100*ec779b8eSAndroid Build Coastguard Worker   int frameNumber = 0;
101*ec779b8eSAndroid Build Coastguard Worker   while (mRunning) {
102*ec779b8eSAndroid Build Coastguard Worker     // Wait for appropriate amount of time to meet configured FPS.
103*ec779b8eSAndroid Build Coastguard Worker     std::chrono::nanoseconds ts = getCurrentTimestamp();
104*ec779b8eSAndroid Build Coastguard Worker     std::chrono::nanoseconds currentDuration = ts - lastFrameTs;
105*ec779b8eSAndroid Build Coastguard Worker     if (currentDuration < frameDuration) {
106*ec779b8eSAndroid Build Coastguard Worker       std::this_thread::sleep_for(frameDuration - currentDuration);
107*ec779b8eSAndroid Build Coastguard Worker     }
108*ec779b8eSAndroid Build Coastguard Worker 
109*ec779b8eSAndroid Build Coastguard Worker     // Render the test pattern and update timestamp.
110*ec779b8eSAndroid Build Coastguard Worker     testPatternProgram.draw(ts);
111*ec779b8eSAndroid Build Coastguard Worker     eglDisplayContext.swapBuffers();
112*ec779b8eSAndroid Build Coastguard Worker     lastFrameTs = getCurrentTimestamp();
113*ec779b8eSAndroid Build Coastguard Worker   }
114*ec779b8eSAndroid Build Coastguard Worker 
115*ec779b8eSAndroid Build Coastguard Worker   ALOGV("Terminating test client render loop");
116*ec779b8eSAndroid Build Coastguard Worker }
117*ec779b8eSAndroid Build Coastguard Worker 
VirtualCameraTestInstance(const int fps)118*ec779b8eSAndroid Build Coastguard Worker VirtualCameraTestInstance::VirtualCameraTestInstance(const int fps)
119*ec779b8eSAndroid Build Coastguard Worker     : mFps(fps) {
120*ec779b8eSAndroid Build Coastguard Worker }
121*ec779b8eSAndroid Build Coastguard Worker 
onStreamConfigured(const int32_t streamId,const Surface & surface,const int32_t width,const int32_t height,const Format pixelFormat)122*ec779b8eSAndroid Build Coastguard Worker ScopedAStatus VirtualCameraTestInstance::onStreamConfigured(
123*ec779b8eSAndroid Build Coastguard Worker     const int32_t streamId, const Surface& surface, const int32_t width,
124*ec779b8eSAndroid Build Coastguard Worker     const int32_t height, const Format pixelFormat) {
125*ec779b8eSAndroid Build Coastguard Worker   ALOGV("%s: streamId %d, %dx%d pixFmt=%s", __func__, streamId, width, height,
126*ec779b8eSAndroid Build Coastguard Worker         toString(pixelFormat).c_str());
127*ec779b8eSAndroid Build Coastguard Worker 
128*ec779b8eSAndroid Build Coastguard Worker   auto renderer = std::make_shared<TestPatternRenderer>(
129*ec779b8eSAndroid Build Coastguard Worker       nativeWindowFromSurface(surface), mFps);
130*ec779b8eSAndroid Build Coastguard Worker 
131*ec779b8eSAndroid Build Coastguard Worker   std::lock_guard<std::mutex> lock(mLock);
132*ec779b8eSAndroid Build Coastguard Worker   if (mInputRenderers.try_emplace(streamId, renderer).second) {
133*ec779b8eSAndroid Build Coastguard Worker     renderer->start();
134*ec779b8eSAndroid Build Coastguard Worker   } else {
135*ec779b8eSAndroid Build Coastguard Worker     ALOGE(
136*ec779b8eSAndroid Build Coastguard Worker         "%s: Input stream with id %d is already active, ignoring "
137*ec779b8eSAndroid Build Coastguard Worker         "onStreamConfigured call",
138*ec779b8eSAndroid Build Coastguard Worker         __func__, streamId);
139*ec779b8eSAndroid Build Coastguard Worker   }
140*ec779b8eSAndroid Build Coastguard Worker 
141*ec779b8eSAndroid Build Coastguard Worker   return ScopedAStatus::ok();
142*ec779b8eSAndroid Build Coastguard Worker }
143*ec779b8eSAndroid Build Coastguard Worker 
onProcessCaptureRequest(const int32_t,const int32_t)144*ec779b8eSAndroid Build Coastguard Worker ScopedAStatus VirtualCameraTestInstance::onProcessCaptureRequest(
145*ec779b8eSAndroid Build Coastguard Worker     const int32_t /*in_streamId*/, const int32_t /*in_frameId*/) {
146*ec779b8eSAndroid Build Coastguard Worker   return ScopedAStatus::ok();
147*ec779b8eSAndroid Build Coastguard Worker }
148*ec779b8eSAndroid Build Coastguard Worker 
onStreamClosed(const int32_t streamId)149*ec779b8eSAndroid Build Coastguard Worker ScopedAStatus VirtualCameraTestInstance::onStreamClosed(const int32_t streamId) {
150*ec779b8eSAndroid Build Coastguard Worker   ALOGV("%s: streamId %d", __func__, streamId);
151*ec779b8eSAndroid Build Coastguard Worker 
152*ec779b8eSAndroid Build Coastguard Worker   std::shared_ptr<TestPatternRenderer> renderer;
153*ec779b8eSAndroid Build Coastguard Worker   {
154*ec779b8eSAndroid Build Coastguard Worker     std::lock_guard<std::mutex> lock(mLock);
155*ec779b8eSAndroid Build Coastguard Worker     auto it = mInputRenderers.find(streamId);
156*ec779b8eSAndroid Build Coastguard Worker     if (it != mInputRenderers.end()) {
157*ec779b8eSAndroid Build Coastguard Worker       renderer = std::move(it->second);
158*ec779b8eSAndroid Build Coastguard Worker       mInputRenderers.erase(it);
159*ec779b8eSAndroid Build Coastguard Worker     }
160*ec779b8eSAndroid Build Coastguard Worker   }
161*ec779b8eSAndroid Build Coastguard Worker   if (renderer != nullptr) {
162*ec779b8eSAndroid Build Coastguard Worker     renderer->stop();
163*ec779b8eSAndroid Build Coastguard Worker   }
164*ec779b8eSAndroid Build Coastguard Worker   return ScopedAStatus::ok();
165*ec779b8eSAndroid Build Coastguard Worker }
166*ec779b8eSAndroid Build Coastguard Worker 
167*ec779b8eSAndroid Build Coastguard Worker }  // namespace virtualcamera
168*ec779b8eSAndroid Build Coastguard Worker }  // namespace companion
169*ec779b8eSAndroid Build Coastguard Worker }  // namespace android
170