• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2020 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include <android-base/logging.h>
18 #include <android/hardware/automotive/evs/1.1/IEvsEnumerator.h>
19 #include <android/hardware/automotive/sv/1.0/ISurroundViewService.h>
20 #include <android/hardware/automotive/sv/1.0/ISurroundView2dSession.h>
21 #include <android/hardware/automotive/sv/1.0/ISurroundView3dSession.h>
22 #include <hidl/HidlTransportSupport.h>
23 #include <stdio.h>
24 #include <utils/StrongPointer.h>
25 #include <utils/Log.h>
26 #include <thread>
27 
28 #include "SurroundViewServiceCallback.h"
29 
30 // libhidl:
31 using android::hardware::configureRpcThreadpool;
32 using android::hardware::joinRpcThreadpool;
33 
34 using android::sp;
35 using android::hardware::Return;
36 using android::hardware::automotive::evs::V1_0::EvsResult;
37 
38 using BufferDesc_1_0  = android::hardware::automotive::evs::V1_0::BufferDesc;
39 using DisplayState = android::hardware::automotive::evs::V1_0::DisplayState;
40 
41 using namespace android::hardware::automotive::sv::V1_0;
42 using namespace android::hardware::automotive::evs::V1_1;
43 
44 const int kLowResolutionWidth = 120;
45 const int kLowResolutionHeight = 90;
46 
47 enum DemoMode {
48     UNKNOWN,
49     DEMO_2D,
50     DEMO_3D,
51 };
52 
53 const float kHorizontalFov = 90;
54 
55 // Number of views to generate.
56 const uint32_t kPoseCount = 16;
57 
58 // Set of pose rotations expressed in quaternions.
59 // Views are generated about a circle at a height about the car, point towards the center.
60 const float kPoseRot[kPoseCount][4] = {
61     {-0.251292, -0.251292, -0.660948, 0.660948},
62     {0.197439, 0.295488, 0.777193, -0.519304},
63     {0.135998, 0.328329, 0.86357, -0.357702},
64     {0.0693313, 0.348552, 0.916761, -0.182355},
65     {-7.76709e-09, 0.355381, 0.934722, 2.0429e-08},
66     {-0.0693313, 0.348552, 0.916761, 0.182355},
67     {-0.135998, 0.328329, 0.86357, 0.357702},
68     {-0.197439, 0.295488, 0.777193, 0.519304},
69     {-0.251292, 0.251292, 0.660948, 0.660948},
70     {-0.295488, 0.197439, 0.519304, 0.777193},
71     {-0.328329, 0.135998, 0.357702, 0.86357},
72     {-0.348552, 0.0693313, 0.182355, 0.916761},
73     {-0.355381, -2.11894e-09, -5.57322e-09, 0.934722},
74     {-0.348552, -0.0693313, -0.182355, 0.916761},
75     {-0.328329, -0.135998, -0.357702, 0.86357},
76     {-0.295488, -0.197439, -0.519304, 0.777193}
77 };
78 
79 // Set of pose translations i.e. positions of the views.
80 // Views are generated about a circle at a height about the car, point towards the center.
81 const float kPoseTrans[kPoseCount][4] = {
82     {4, 0, 2.5},
83     {3.69552, 1.53073, 2.5},
84     {2.82843, 2.82843, 2.5},
85     {1.53073, 3.69552, 2.5},
86     {-1.74846e-07, 4, 2.5},
87     {-1.53073, 3.69552, 2.5},
88     {-2.82843, 2.82843, 2.5},
89     {-3.69552, 1.53073, 2.5},
90     {-4, -3.49691e-07, 2.5},
91     {-3.69552, -1.53073, 2.5},
92     {-2.82843, -2.82843, 2.5},
93     {-1.53073, -3.69552, 2.5},
94     {4.76995e-08, -4, 2.5},
95     {1.53073, -3.69552, 2.5},
96     {2.82843, -2.82843, 2.5},
97     {3.69552, -1.53073, 2.5}
98 };
99 
run2dSurroundView(sp<ISurroundViewService> pSurroundViewService,sp<IEvsDisplay> pDisplay)100 bool run2dSurroundView(sp<ISurroundViewService> pSurroundViewService,
101                        sp<IEvsDisplay> pDisplay) {
102     LOG(INFO) << "Run 2d Surround View demo";
103 
104     // Call HIDL API "start2dSession"
105     sp<ISurroundView2dSession> surroundView2dSession;
106 
107     SvResult svResult;
108     pSurroundViewService->start2dSession(
109         [&surroundView2dSession, &svResult](
110             const sp<ISurroundView2dSession>& session, SvResult result) {
111         surroundView2dSession = session;
112         svResult = result;
113     });
114 
115     if (surroundView2dSession == nullptr || svResult != SvResult::OK) {
116         LOG(ERROR) << "Failed to start2dSession";
117         return false;
118     } else {
119         LOG(INFO) << "start2dSession succeeded";
120     }
121 
122     sp<SurroundViewServiceCallback> sv2dCallback
123         = new SurroundViewServiceCallback(pDisplay, surroundView2dSession);
124 
125     // Start 2d stream with callback
126     if (surroundView2dSession->startStream(sv2dCallback) != SvResult::OK) {
127         LOG(ERROR) << "Failed to start 2d stream";
128         return false;
129     }
130 
131     // Let the SV algorithm run for 10 seconds for HIGH_QUALITY
132     std::this_thread::sleep_for(std::chrono::seconds(10));
133 
134     // Switch to low quality and lower resolution
135     Sv2dConfig config;
136     config.width = kLowResolutionWidth;
137     config.blending = SvQuality::LOW;
138     if (surroundView2dSession->set2dConfig(config) != SvResult::OK) {
139         LOG(ERROR) << "Failed to set2dConfig";
140         return false;
141     }
142 
143     // Let the SV algorithm run for 10 seconds for LOW_QUALITY
144     std::this_thread::sleep_for(std::chrono::seconds(10));
145 
146     // TODO(b/150412555): wait for the last frame
147     // Stop the 2d stream and session
148     surroundView2dSession->stopStream();
149 
150     pSurroundViewService->stop2dSession(surroundView2dSession);
151     surroundView2dSession = nullptr;
152 
153     LOG(INFO) << "SV 2D session finished.";
154 
155     return true;
156 };
157 
158 // Given a valid sv 3d session and pose, viewid and hfov parameters, sets the view.
setView(sp<ISurroundView3dSession> surroundView3dSession,uint32_t viewId,uint32_t poseIndex,float hfov)159 bool setView(sp<ISurroundView3dSession> surroundView3dSession, uint32_t viewId,
160         uint32_t poseIndex, float hfov)
161 {
162     const View3d view3d = {
163         .viewId = viewId,
164         .pose = {
165             .rotation = {.x=kPoseRot[poseIndex][0], .y=kPoseRot[poseIndex][1],
166                     .z=kPoseRot[poseIndex][2], .w=kPoseRot[poseIndex][3]},
167             .translation = {.x=kPoseTrans[poseIndex][0], .y=kPoseTrans[poseIndex][1],
168                     .z=kPoseTrans[poseIndex][2]},
169         },
170         .horizontalFov = hfov,
171     };
172 
173     const std::vector<View3d> views = {view3d};
174     if (surroundView3dSession->setViews(views) != SvResult::OK) {
175         return false;
176     }
177     return true;
178 }
179 
run3dSurroundView(sp<ISurroundViewService> pSurroundViewService,sp<IEvsDisplay> pDisplay)180 bool run3dSurroundView(sp<ISurroundViewService> pSurroundViewService,
181                        sp<IEvsDisplay> pDisplay) {
182     LOG(INFO) << "Run 3d Surround View demo";
183 
184     // Call HIDL API "start3dSession"
185     sp<ISurroundView3dSession> surroundView3dSession;
186 
187     SvResult svResult;
188     pSurroundViewService->start3dSession(
189         [&surroundView3dSession, &svResult](
190             const sp<ISurroundView3dSession>& session, SvResult result) {
191         surroundView3dSession = session;
192         svResult = result;
193     });
194 
195     if (surroundView3dSession == nullptr || svResult != SvResult::OK) {
196         LOG(ERROR) << "Failed to start3dSession";
197         return false;
198     } else {
199         LOG(INFO) << "start3dSession succeeded";
200     }
201 
202     sp<SurroundViewServiceCallback> sv3dCallback
203         = new SurroundViewServiceCallback(pDisplay, surroundView3dSession);
204 
205     // A view must be set before the 3d stream is started.
206     if (!setView(surroundView3dSession, 0, 0, kHorizontalFov)) {
207         LOG(ERROR) << "Failed to setView of pose index :" << 0;
208         return false;
209     }
210 
211     // Start 3d stream with callback
212     if (surroundView3dSession->startStream(sv3dCallback) != SvResult::OK) {
213         LOG(ERROR) << "Failed to start 3d stream";
214         return false;
215     }
216 
217     // Let the SV algorithm run for 10 seconds for HIGH_QUALITY
218     const int totalViewingTimeSecs = 10;
219     const std::chrono::milliseconds
220             perPoseSleepTimeMs(totalViewingTimeSecs * 1000 / kPoseCount);
221     for(uint32_t i = 1; i < kPoseCount; i++) {
222         if (!setView(surroundView3dSession, i, i, kHorizontalFov)) {
223             LOG(WARNING) << "Failed to setView of pose index :" << i;
224         }
225         std::this_thread::sleep_for(perPoseSleepTimeMs);
226     }
227 
228     // Switch to low quality and lower resolution
229     Sv3dConfig config;
230     config.width = kLowResolutionWidth;
231     config.height = kLowResolutionHeight;
232     config.carDetails = SvQuality::LOW;
233     if (surroundView3dSession->set3dConfig(config) != SvResult::OK) {
234         LOG(ERROR) << "Failed to set3dConfig";
235         return false;
236     }
237 
238     // Let the SV algorithm run for 10 seconds for LOW_QUALITY
239     for(uint32_t i = 0; i < kPoseCount; i++) {
240         if(!setView(surroundView3dSession, i + kPoseCount, i, kHorizontalFov)) {
241             LOG(WARNING) << "Failed to setView of pose index :" << i;
242         }
243         std::this_thread::sleep_for(perPoseSleepTimeMs);
244     }
245 
246     // TODO(b/150412555): wait for the last frame
247     // Stop the 3d stream and session
248     surroundView3dSession->stopStream();
249 
250     pSurroundViewService->stop3dSession(surroundView3dSession);
251     surroundView3dSession = nullptr;
252 
253     LOG(DEBUG) << "SV 3D session finished.";
254 
255     return true;
256 };
257 
258 // Main entry point
main(int argc,char ** argv)259 int main(int argc, char** argv) {
260     // Start up
261     LOG(INFO) << "SV app starting";
262 
263     DemoMode mode = UNKNOWN;
264     for (int i=1; i< argc; i++) {
265         if (strcmp(argv[i], "--use2d") == 0) {
266             mode = DEMO_2D;
267         } else if (strcmp(argv[i], "--use3d") == 0) {
268             mode = DEMO_3D;
269         } else {
270             LOG(WARNING) << "Ignoring unrecognized command line arg: "
271                          << argv[i];
272         }
273     }
274 
275     if (mode == UNKNOWN) {
276         LOG(ERROR) << "No demo mode is specified. Exiting";
277         return EXIT_FAILURE;
278     }
279 
280     // Set thread pool size to one to avoid concurrent events from the HAL.
281     // This pool will handle the SurroundViewStream callbacks.
282     configureRpcThreadpool(1, false /* callerWillJoin */);
283 
284     // Try to connect to EVS service
285     LOG(INFO) << "Acquiring EVS Enumerator";
286     sp<IEvsEnumerator> evs = IEvsEnumerator::getService();
287     if (evs == nullptr) {
288         LOG(ERROR) << "getService(default) returned NULL.  Exiting.";
289         return EXIT_FAILURE;
290     }
291 
292     // Try to connect to SV service
293     LOG(INFO) << "Acquiring SV Service";
294     android::sp<ISurroundViewService> surroundViewService
295         = ISurroundViewService::getService("default");
296 
297     if (surroundViewService == nullptr) {
298         LOG(ERROR) << "getService(default) returned NULL.";
299         return EXIT_FAILURE;
300     } else {
301         LOG(INFO) << "Get ISurroundViewService default";
302     }
303 
304     // Connect to evs display
305     int displayId;
306     evs->getDisplayIdList([&displayId](auto idList) {
307         displayId = idList[0];
308     });
309 
310     LOG(INFO) << "Acquiring EVS Display with ID: "
311               << displayId;
312     sp<IEvsDisplay> display = evs->openDisplay_1_1(displayId);
313     if (display == nullptr) {
314         LOG(ERROR) << "EVS Display unavailable.  Exiting.";
315         return EXIT_FAILURE;
316     }
317 
318     if (mode == DEMO_2D) {
319         if (!run2dSurroundView(surroundViewService, display)) {
320             LOG(ERROR) << "Something went wrong in 2d surround view demo. "
321                        << "Exiting.";
322             return EXIT_FAILURE;
323         }
324     } else if (mode == DEMO_3D) {
325         if (!run3dSurroundView(surroundViewService, display)) {
326             LOG(ERROR) << "Something went wrong in 3d surround view demo. "
327                        << "Exiting.";
328             return EXIT_FAILURE;
329         }
330     }
331 
332     evs->closeDisplay(display);
333 
334     LOG(DEBUG) << "SV sample app finished running successfully";
335     return EXIT_SUCCESS;
336 }
337