1*ec779b8eSAndroid Build Coastguard Worker /*
2*ec779b8eSAndroid Build Coastguard Worker * Copyright (C) 2021 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 #include <inttypes.h>
17*ec779b8eSAndroid Build Coastguard Worker
18*ec779b8eSAndroid Build Coastguard Worker #include <android-base/stringprintf.h>
19*ec779b8eSAndroid Build Coastguard Worker #include <audio_utils/SimpleLog.h>
20*ec779b8eSAndroid Build Coastguard Worker #include "media/HeadTrackingProcessor.h"
21*ec779b8eSAndroid Build Coastguard Worker #include "media/QuaternionUtil.h"
22*ec779b8eSAndroid Build Coastguard Worker
23*ec779b8eSAndroid Build Coastguard Worker #include "ModeSelector.h"
24*ec779b8eSAndroid Build Coastguard Worker #include "PoseBias.h"
25*ec779b8eSAndroid Build Coastguard Worker #include "PosePredictor.h"
26*ec779b8eSAndroid Build Coastguard Worker #include "ScreenHeadFusion.h"
27*ec779b8eSAndroid Build Coastguard Worker #include "StillnessDetector.h"
28*ec779b8eSAndroid Build Coastguard Worker
29*ec779b8eSAndroid Build Coastguard Worker namespace android {
30*ec779b8eSAndroid Build Coastguard Worker namespace media {
31*ec779b8eSAndroid Build Coastguard Worker namespace {
32*ec779b8eSAndroid Build Coastguard Worker
33*ec779b8eSAndroid Build Coastguard Worker using android::base::StringAppendF;
34*ec779b8eSAndroid Build Coastguard Worker using Eigen::Quaternionf;
35*ec779b8eSAndroid Build Coastguard Worker using Eigen::Vector3f;
36*ec779b8eSAndroid Build Coastguard Worker
37*ec779b8eSAndroid Build Coastguard Worker class HeadTrackingProcessorImpl : public HeadTrackingProcessor {
38*ec779b8eSAndroid Build Coastguard Worker public:
HeadTrackingProcessorImpl(const Options & options,HeadTrackingMode initialMode)39*ec779b8eSAndroid Build Coastguard Worker HeadTrackingProcessorImpl(const Options& options, HeadTrackingMode initialMode)
40*ec779b8eSAndroid Build Coastguard Worker : mOptions(options),
41*ec779b8eSAndroid Build Coastguard Worker mHeadStillnessDetector(StillnessDetector::Options{
42*ec779b8eSAndroid Build Coastguard Worker .defaultValue = false,
43*ec779b8eSAndroid Build Coastguard Worker .windowDuration = options.autoRecenterWindowDuration,
44*ec779b8eSAndroid Build Coastguard Worker .translationalThreshold = options.autoRecenterTranslationalThreshold,
45*ec779b8eSAndroid Build Coastguard Worker .rotationalThreshold = options.autoRecenterRotationalThreshold,
46*ec779b8eSAndroid Build Coastguard Worker }),
47*ec779b8eSAndroid Build Coastguard Worker mScreenStillnessDetector(StillnessDetector::Options{
48*ec779b8eSAndroid Build Coastguard Worker .defaultValue = true,
49*ec779b8eSAndroid Build Coastguard Worker .windowDuration = options.screenStillnessWindowDuration,
50*ec779b8eSAndroid Build Coastguard Worker .translationalThreshold = options.screenStillnessTranslationalThreshold,
51*ec779b8eSAndroid Build Coastguard Worker .rotationalThreshold = options.screenStillnessRotationalThreshold,
52*ec779b8eSAndroid Build Coastguard Worker }),
53*ec779b8eSAndroid Build Coastguard Worker mModeSelector(ModeSelector::Options{.freshnessTimeout = options.freshnessTimeout},
54*ec779b8eSAndroid Build Coastguard Worker initialMode),
55*ec779b8eSAndroid Build Coastguard Worker mRateLimiter(PoseRateLimiter::Options{
56*ec779b8eSAndroid Build Coastguard Worker .maxTranslationalVelocity = options.maxTranslationalVelocity,
57*ec779b8eSAndroid Build Coastguard Worker .maxRotationalVelocity = options.maxRotationalVelocity}) {}
58*ec779b8eSAndroid Build Coastguard Worker
setDesiredMode(HeadTrackingMode mode)59*ec779b8eSAndroid Build Coastguard Worker void setDesiredMode(HeadTrackingMode mode) override { mModeSelector.setDesiredMode(mode); }
60*ec779b8eSAndroid Build Coastguard Worker
setWorldToHeadPose(int64_t timestamp,const Pose3f & worldToHead,const Twist3f & headTwist)61*ec779b8eSAndroid Build Coastguard Worker void setWorldToHeadPose(int64_t timestamp, const Pose3f& worldToHead,
62*ec779b8eSAndroid Build Coastguard Worker const Twist3f& headTwist) override {
63*ec779b8eSAndroid Build Coastguard Worker const Pose3f predictedWorldToHead = mPosePredictor.predict(
64*ec779b8eSAndroid Build Coastguard Worker timestamp, worldToHead, headTwist, mOptions.predictionDuration);
65*ec779b8eSAndroid Build Coastguard Worker mHeadPoseBias.setInput(predictedWorldToHead);
66*ec779b8eSAndroid Build Coastguard Worker mHeadStillnessDetector.setInput(timestamp, predictedWorldToHead);
67*ec779b8eSAndroid Build Coastguard Worker mWorldToHeadTimestamp = timestamp;
68*ec779b8eSAndroid Build Coastguard Worker }
69*ec779b8eSAndroid Build Coastguard Worker
setWorldToScreenPose(int64_t timestamp,const Pose3f & worldToScreen)70*ec779b8eSAndroid Build Coastguard Worker void setWorldToScreenPose(int64_t timestamp, const Pose3f& worldToScreen) override {
71*ec779b8eSAndroid Build Coastguard Worker if (mPhysicalToLogicalAngle != mPendingPhysicalToLogicalAngle) {
72*ec779b8eSAndroid Build Coastguard Worker // We're introducing an artificial discontinuity. Enable the rate limiter.
73*ec779b8eSAndroid Build Coastguard Worker mRateLimiter.enable();
74*ec779b8eSAndroid Build Coastguard Worker mPhysicalToLogicalAngle = mPendingPhysicalToLogicalAngle;
75*ec779b8eSAndroid Build Coastguard Worker }
76*ec779b8eSAndroid Build Coastguard Worker
77*ec779b8eSAndroid Build Coastguard Worker Pose3f worldToLogicalScreen = worldToScreen * Pose3f(rotateY(-mPhysicalToLogicalAngle));
78*ec779b8eSAndroid Build Coastguard Worker mScreenPoseBias.setInput(worldToLogicalScreen);
79*ec779b8eSAndroid Build Coastguard Worker mScreenStillnessDetector.setInput(timestamp, worldToLogicalScreen);
80*ec779b8eSAndroid Build Coastguard Worker mWorldToScreenTimestamp = timestamp;
81*ec779b8eSAndroid Build Coastguard Worker }
82*ec779b8eSAndroid Build Coastguard Worker
setScreenToStagePose(const Pose3f & screenToStage)83*ec779b8eSAndroid Build Coastguard Worker void setScreenToStagePose(const Pose3f& screenToStage) override {
84*ec779b8eSAndroid Build Coastguard Worker mModeSelector.setScreenToStagePose(screenToStage);
85*ec779b8eSAndroid Build Coastguard Worker }
86*ec779b8eSAndroid Build Coastguard Worker
setDisplayOrientation(float physicalToLogicalAngle)87*ec779b8eSAndroid Build Coastguard Worker void setDisplayOrientation(float physicalToLogicalAngle) override {
88*ec779b8eSAndroid Build Coastguard Worker mPendingPhysicalToLogicalAngle = physicalToLogicalAngle;
89*ec779b8eSAndroid Build Coastguard Worker }
90*ec779b8eSAndroid Build Coastguard Worker
calculate(int64_t timestamp)91*ec779b8eSAndroid Build Coastguard Worker void calculate(int64_t timestamp) override {
92*ec779b8eSAndroid Build Coastguard Worker bool screenStable = true;
93*ec779b8eSAndroid Build Coastguard Worker
94*ec779b8eSAndroid Build Coastguard Worker // Handle the screen first, since it might: trigger a recentering of the head.
95*ec779b8eSAndroid Build Coastguard Worker if (mWorldToScreenTimestamp.has_value()) {
96*ec779b8eSAndroid Build Coastguard Worker const Pose3f worldToLogicalScreen = mScreenPoseBias.getOutput();
97*ec779b8eSAndroid Build Coastguard Worker screenStable = mScreenStillnessDetector.calculate(timestamp);
98*ec779b8eSAndroid Build Coastguard Worker mModeSelector.setScreenStable(mWorldToScreenTimestamp.value(), screenStable);
99*ec779b8eSAndroid Build Coastguard Worker // Whenever the screen is unstable, recenter the head pose.
100*ec779b8eSAndroid Build Coastguard Worker if (!screenStable) {
101*ec779b8eSAndroid Build Coastguard Worker recenter(true, false, "calculate: screen movement");
102*ec779b8eSAndroid Build Coastguard Worker }
103*ec779b8eSAndroid Build Coastguard Worker mScreenHeadFusion.setWorldToScreenPose(mWorldToScreenTimestamp.value(),
104*ec779b8eSAndroid Build Coastguard Worker worldToLogicalScreen);
105*ec779b8eSAndroid Build Coastguard Worker }
106*ec779b8eSAndroid Build Coastguard Worker
107*ec779b8eSAndroid Build Coastguard Worker // Handle head.
108*ec779b8eSAndroid Build Coastguard Worker if (mWorldToHeadTimestamp.has_value()) {
109*ec779b8eSAndroid Build Coastguard Worker Pose3f worldToHead = mHeadPoseBias.getOutput();
110*ec779b8eSAndroid Build Coastguard Worker // Auto-recenter.
111*ec779b8eSAndroid Build Coastguard Worker bool headStable = mHeadStillnessDetector.calculate(timestamp);
112*ec779b8eSAndroid Build Coastguard Worker if (headStable || !screenStable) {
113*ec779b8eSAndroid Build Coastguard Worker recenter(true, false, "calculate: head movement");
114*ec779b8eSAndroid Build Coastguard Worker worldToHead = mHeadPoseBias.getOutput();
115*ec779b8eSAndroid Build Coastguard Worker }
116*ec779b8eSAndroid Build Coastguard Worker
117*ec779b8eSAndroid Build Coastguard Worker mScreenHeadFusion.setWorldToHeadPose(mWorldToHeadTimestamp.value(), worldToHead);
118*ec779b8eSAndroid Build Coastguard Worker mModeSelector.setWorldToHeadPose(mWorldToHeadTimestamp.value(), worldToHead);
119*ec779b8eSAndroid Build Coastguard Worker }
120*ec779b8eSAndroid Build Coastguard Worker
121*ec779b8eSAndroid Build Coastguard Worker auto maybeScreenToHead = mScreenHeadFusion.calculate();
122*ec779b8eSAndroid Build Coastguard Worker if (maybeScreenToHead.has_value()) {
123*ec779b8eSAndroid Build Coastguard Worker mModeSelector.setScreenToHeadPose(maybeScreenToHead->timestamp,
124*ec779b8eSAndroid Build Coastguard Worker maybeScreenToHead->pose);
125*ec779b8eSAndroid Build Coastguard Worker } else {
126*ec779b8eSAndroid Build Coastguard Worker mModeSelector.setScreenToHeadPose(timestamp, std::nullopt);
127*ec779b8eSAndroid Build Coastguard Worker }
128*ec779b8eSAndroid Build Coastguard Worker
129*ec779b8eSAndroid Build Coastguard Worker HeadTrackingMode prevMode = mModeSelector.getActualMode();
130*ec779b8eSAndroid Build Coastguard Worker mModeSelector.calculate(timestamp);
131*ec779b8eSAndroid Build Coastguard Worker if (mModeSelector.getActualMode() != prevMode) {
132*ec779b8eSAndroid Build Coastguard Worker // Mode has changed, enable rate limiting.
133*ec779b8eSAndroid Build Coastguard Worker mRateLimiter.enable();
134*ec779b8eSAndroid Build Coastguard Worker }
135*ec779b8eSAndroid Build Coastguard Worker mRateLimiter.setTarget(mModeSelector.getHeadToStagePose());
136*ec779b8eSAndroid Build Coastguard Worker mHeadToStagePose = mRateLimiter.calculatePose(timestamp);
137*ec779b8eSAndroid Build Coastguard Worker }
138*ec779b8eSAndroid Build Coastguard Worker
getHeadToStagePose() const139*ec779b8eSAndroid Build Coastguard Worker Pose3f getHeadToStagePose() const override { return mHeadToStagePose; }
140*ec779b8eSAndroid Build Coastguard Worker
getActualMode() const141*ec779b8eSAndroid Build Coastguard Worker HeadTrackingMode getActualMode() const override { return mModeSelector.getActualMode(); }
142*ec779b8eSAndroid Build Coastguard Worker
recenter(bool recenterHead,bool recenterScreen,std::string source)143*ec779b8eSAndroid Build Coastguard Worker void recenter(bool recenterHead, bool recenterScreen, std::string source) override {
144*ec779b8eSAndroid Build Coastguard Worker if (recenterHead) {
145*ec779b8eSAndroid Build Coastguard Worker mHeadPoseBias.recenter();
146*ec779b8eSAndroid Build Coastguard Worker mHeadStillnessDetector.reset();
147*ec779b8eSAndroid Build Coastguard Worker mLocalLog.log("recenter Head from %s", source.c_str());
148*ec779b8eSAndroid Build Coastguard Worker }
149*ec779b8eSAndroid Build Coastguard Worker if (recenterScreen) {
150*ec779b8eSAndroid Build Coastguard Worker mScreenPoseBias.recenter();
151*ec779b8eSAndroid Build Coastguard Worker mScreenStillnessDetector.reset();
152*ec779b8eSAndroid Build Coastguard Worker mLocalLog.log("recenter Screen from %s", source.c_str());
153*ec779b8eSAndroid Build Coastguard Worker }
154*ec779b8eSAndroid Build Coastguard Worker
155*ec779b8eSAndroid Build Coastguard Worker // If a sensor being recentered is included in the current mode, apply rate limiting to
156*ec779b8eSAndroid Build Coastguard Worker // avoid discontinuities.
157*ec779b8eSAndroid Build Coastguard Worker HeadTrackingMode mode = mModeSelector.getActualMode();
158*ec779b8eSAndroid Build Coastguard Worker if ((recenterHead && (mode == HeadTrackingMode::WORLD_RELATIVE ||
159*ec779b8eSAndroid Build Coastguard Worker mode == HeadTrackingMode::SCREEN_RELATIVE)) ||
160*ec779b8eSAndroid Build Coastguard Worker (recenterScreen && mode == HeadTrackingMode::SCREEN_RELATIVE)) {
161*ec779b8eSAndroid Build Coastguard Worker mRateLimiter.enable();
162*ec779b8eSAndroid Build Coastguard Worker }
163*ec779b8eSAndroid Build Coastguard Worker }
164*ec779b8eSAndroid Build Coastguard Worker
setPosePredictorType(PosePredictorType type)165*ec779b8eSAndroid Build Coastguard Worker void setPosePredictorType(PosePredictorType type) override {
166*ec779b8eSAndroid Build Coastguard Worker mPosePredictor.setPosePredictorType(type);
167*ec779b8eSAndroid Build Coastguard Worker }
168*ec779b8eSAndroid Build Coastguard Worker
toString_l(unsigned level) const169*ec779b8eSAndroid Build Coastguard Worker std::string toString_l(unsigned level) const override {
170*ec779b8eSAndroid Build Coastguard Worker std::string prefixSpace(level, ' ');
171*ec779b8eSAndroid Build Coastguard Worker std::string ss = prefixSpace + "HeadTrackingProcessor:\n";
172*ec779b8eSAndroid Build Coastguard Worker StringAppendF(&ss, "%s maxTranslationalVelocity: %f meter/second\n", prefixSpace.c_str(),
173*ec779b8eSAndroid Build Coastguard Worker mOptions.maxTranslationalVelocity);
174*ec779b8eSAndroid Build Coastguard Worker StringAppendF(&ss, "%s maxRotationalVelocity: %f rad/second\n", prefixSpace.c_str(),
175*ec779b8eSAndroid Build Coastguard Worker mOptions.maxRotationalVelocity);
176*ec779b8eSAndroid Build Coastguard Worker StringAppendF(&ss, "%s freshnessTimeout: %0.4f ms\n", prefixSpace.c_str(),
177*ec779b8eSAndroid Build Coastguard Worker media::nsToFloatMs(mOptions.freshnessTimeout));
178*ec779b8eSAndroid Build Coastguard Worker StringAppendF(&ss, "%s predictionDuration: %0.4f ms\n", prefixSpace.c_str(),
179*ec779b8eSAndroid Build Coastguard Worker media::nsToFloatMs(mOptions.predictionDuration));
180*ec779b8eSAndroid Build Coastguard Worker StringAppendF(&ss, "%s autoRecenterWindowDuration: %0.4f ms\n", prefixSpace.c_str(),
181*ec779b8eSAndroid Build Coastguard Worker media::nsToFloatMs(mOptions.autoRecenterWindowDuration));
182*ec779b8eSAndroid Build Coastguard Worker StringAppendF(&ss, "%s autoRecenterTranslationalThreshold: %f meter\n", prefixSpace.c_str(),
183*ec779b8eSAndroid Build Coastguard Worker mOptions.autoRecenterTranslationalThreshold);
184*ec779b8eSAndroid Build Coastguard Worker StringAppendF(&ss, "%s autoRecenterRotationalThreshold: %f radians\n", prefixSpace.c_str(),
185*ec779b8eSAndroid Build Coastguard Worker mOptions.autoRecenterRotationalThreshold);
186*ec779b8eSAndroid Build Coastguard Worker StringAppendF(&ss, "%s screenStillnessWindowDuration: %0.4f ms\n", prefixSpace.c_str(),
187*ec779b8eSAndroid Build Coastguard Worker media::nsToFloatMs(mOptions.screenStillnessWindowDuration));
188*ec779b8eSAndroid Build Coastguard Worker StringAppendF(&ss, "%s screenStillnessTranslationalThreshold: %f meter\n",
189*ec779b8eSAndroid Build Coastguard Worker prefixSpace.c_str(), mOptions.screenStillnessTranslationalThreshold);
190*ec779b8eSAndroid Build Coastguard Worker StringAppendF(&ss, "%s screenStillnessRotationalThreshold: %f radians\n",
191*ec779b8eSAndroid Build Coastguard Worker prefixSpace.c_str(), mOptions.screenStillnessRotationalThreshold);
192*ec779b8eSAndroid Build Coastguard Worker ss += mModeSelector.toString(level + 1);
193*ec779b8eSAndroid Build Coastguard Worker ss += mRateLimiter.toString(level + 1);
194*ec779b8eSAndroid Build Coastguard Worker ss += mPosePredictor.toString(level + 1);
195*ec779b8eSAndroid Build Coastguard Worker ss.append(prefixSpace + "ReCenterHistory:\n");
196*ec779b8eSAndroid Build Coastguard Worker ss += mLocalLog.dumpToString((prefixSpace + " ").c_str(), mMaxLocalLogLine);
197*ec779b8eSAndroid Build Coastguard Worker return ss;
198*ec779b8eSAndroid Build Coastguard Worker }
199*ec779b8eSAndroid Build Coastguard Worker
200*ec779b8eSAndroid Build Coastguard Worker private:
201*ec779b8eSAndroid Build Coastguard Worker const Options mOptions;
202*ec779b8eSAndroid Build Coastguard Worker float mPhysicalToLogicalAngle = 0;
203*ec779b8eSAndroid Build Coastguard Worker // We store the physical to logical angle as "pending" until the next world-to-screen sample it
204*ec779b8eSAndroid Build Coastguard Worker // applies to arrives.
205*ec779b8eSAndroid Build Coastguard Worker float mPendingPhysicalToLogicalAngle = 0;
206*ec779b8eSAndroid Build Coastguard Worker std::optional<int64_t> mWorldToHeadTimestamp;
207*ec779b8eSAndroid Build Coastguard Worker std::optional<int64_t> mWorldToScreenTimestamp;
208*ec779b8eSAndroid Build Coastguard Worker Pose3f mHeadToStagePose;
209*ec779b8eSAndroid Build Coastguard Worker PoseBias mHeadPoseBias;
210*ec779b8eSAndroid Build Coastguard Worker PoseBias mScreenPoseBias;
211*ec779b8eSAndroid Build Coastguard Worker StillnessDetector mHeadStillnessDetector;
212*ec779b8eSAndroid Build Coastguard Worker StillnessDetector mScreenStillnessDetector;
213*ec779b8eSAndroid Build Coastguard Worker ScreenHeadFusion mScreenHeadFusion;
214*ec779b8eSAndroid Build Coastguard Worker ModeSelector mModeSelector;
215*ec779b8eSAndroid Build Coastguard Worker PoseRateLimiter mRateLimiter;
216*ec779b8eSAndroid Build Coastguard Worker PosePredictor mPosePredictor;
217*ec779b8eSAndroid Build Coastguard Worker static constexpr std::size_t mMaxLocalLogLine = 10;
218*ec779b8eSAndroid Build Coastguard Worker SimpleLog mLocalLog{mMaxLocalLogLine};
219*ec779b8eSAndroid Build Coastguard Worker };
220*ec779b8eSAndroid Build Coastguard Worker
221*ec779b8eSAndroid Build Coastguard Worker } // namespace
222*ec779b8eSAndroid Build Coastguard Worker
createHeadTrackingProcessor(const HeadTrackingProcessor::Options & options,HeadTrackingMode initialMode)223*ec779b8eSAndroid Build Coastguard Worker std::unique_ptr<HeadTrackingProcessor> createHeadTrackingProcessor(
224*ec779b8eSAndroid Build Coastguard Worker const HeadTrackingProcessor::Options& options, HeadTrackingMode initialMode) {
225*ec779b8eSAndroid Build Coastguard Worker return std::make_unique<HeadTrackingProcessorImpl>(options, initialMode);
226*ec779b8eSAndroid Build Coastguard Worker }
227*ec779b8eSAndroid Build Coastguard Worker
toString(HeadTrackingMode mode)228*ec779b8eSAndroid Build Coastguard Worker std::string toString(HeadTrackingMode mode) {
229*ec779b8eSAndroid Build Coastguard Worker switch (mode) {
230*ec779b8eSAndroid Build Coastguard Worker case HeadTrackingMode::STATIC:
231*ec779b8eSAndroid Build Coastguard Worker return "STATIC";
232*ec779b8eSAndroid Build Coastguard Worker case HeadTrackingMode::WORLD_RELATIVE:
233*ec779b8eSAndroid Build Coastguard Worker return "WORLD_RELATIVE";
234*ec779b8eSAndroid Build Coastguard Worker case HeadTrackingMode::SCREEN_RELATIVE:
235*ec779b8eSAndroid Build Coastguard Worker return "SCREEN_RELATIVE";
236*ec779b8eSAndroid Build Coastguard Worker }
237*ec779b8eSAndroid Build Coastguard Worker return "EnumNotImplemented";
238*ec779b8eSAndroid Build Coastguard Worker };
239*ec779b8eSAndroid Build Coastguard Worker
toString(PosePredictorType posePredictorType)240*ec779b8eSAndroid Build Coastguard Worker std::string toString(PosePredictorType posePredictorType) {
241*ec779b8eSAndroid Build Coastguard Worker switch (posePredictorType) {
242*ec779b8eSAndroid Build Coastguard Worker case PosePredictorType::AUTO: return "AUTO";
243*ec779b8eSAndroid Build Coastguard Worker case PosePredictorType::LAST: return "LAST";
244*ec779b8eSAndroid Build Coastguard Worker case PosePredictorType::TWIST: return "TWIST";
245*ec779b8eSAndroid Build Coastguard Worker case PosePredictorType::LEAST_SQUARES: return "LEAST_SQUARES";
246*ec779b8eSAndroid Build Coastguard Worker }
247*ec779b8eSAndroid Build Coastguard Worker return "UNKNOWN" + std::to_string((int)posePredictorType);
248*ec779b8eSAndroid Build Coastguard Worker }
249*ec779b8eSAndroid Build Coastguard Worker
isValidPosePredictorType(PosePredictorType posePredictorType)250*ec779b8eSAndroid Build Coastguard Worker bool isValidPosePredictorType(PosePredictorType posePredictorType) {
251*ec779b8eSAndroid Build Coastguard Worker switch (posePredictorType) {
252*ec779b8eSAndroid Build Coastguard Worker case PosePredictorType::AUTO:
253*ec779b8eSAndroid Build Coastguard Worker case PosePredictorType::LAST:
254*ec779b8eSAndroid Build Coastguard Worker case PosePredictorType::TWIST:
255*ec779b8eSAndroid Build Coastguard Worker case PosePredictorType::LEAST_SQUARES:
256*ec779b8eSAndroid Build Coastguard Worker return true;
257*ec779b8eSAndroid Build Coastguard Worker }
258*ec779b8eSAndroid Build Coastguard Worker return false;
259*ec779b8eSAndroid Build Coastguard Worker }
260*ec779b8eSAndroid Build Coastguard Worker
261*ec779b8eSAndroid Build Coastguard Worker } // namespace media
262*ec779b8eSAndroid Build Coastguard Worker } // namespace android
263