1 /*
2 * Copyright (C) 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 "SurroundView3dSession.h"
18
19 #include <set>
20
21 #include <utils/Log.h>
22 #include <utils/SystemClock.h>
23
24 #include <android/hidl/memory/1.0/IMemory.h>
25 #include <hidlmemory/mapping.h>
26
27 using ::android::hidl::memory::V1_0::IMemory;
28 using ::android::hardware::hidl_memory;
29
30 namespace android {
31 namespace hardware {
32 namespace automotive {
33 namespace sv {
34 namespace V1_0 {
35 namespace implementation {
36
SurroundView3dSession()37 SurroundView3dSession::SurroundView3dSession() :
38 mStreamState(STOPPED){
39
40 mEvsCameraIds = {"0" , "1", "2", "3"};
41
42 mConfig.width = 640;
43 mConfig.height = 480;
44 mConfig.carDetails = SvQuality::HIGH;
45
46 framesRecord.frames.svBuffers.resize(1);
47 framesRecord.frames.svBuffers[0].viewId = 0;
48 framesRecord.frames.svBuffers[0].hardwareBuffer.nativeHandle = new native_handle_t();
49 framesRecord.frames.svBuffers[0].hardwareBuffer.description[0] = mConfig.width;
50 framesRecord.frames.svBuffers[0].hardwareBuffer.description[1] = mConfig.height;
51 }
52
53 // Methods from ::android::hardware::automotive::sv::V1_0::ISurroundViewSession.
startStream(const sp<ISurroundViewStream> & stream)54 Return<SvResult> SurroundView3dSession::startStream(
55 const sp<ISurroundViewStream>& stream) {
56 ALOGD("SurroundView3dSession::startStream");
57 std::lock_guard<std::mutex> lock(mAccessLock);
58
59 if (mStreamState != STOPPED) {
60 ALOGE("ignoring startVideoStream call when a stream is already running.");
61 return SvResult::INTERNAL_ERROR;
62 }
63
64 if (mViews.empty()) {
65 ALOGE("No views have been set for current Surround View 3d Session. "
66 "Please call setViews before starting the stream.");
67 return SvResult::VIEW_NOT_SET;
68 }
69
70 mStream = stream;
71
72 ALOGD("Notify SvEvent::STREAM_STARTED");
73 mStream->notify(SvEvent::STREAM_STARTED);
74
75 // Start the frame generation thread
76 mStreamState = RUNNING;
77 mCaptureThread = std::thread([this](){ generateFrames(); });
78
79 return SvResult::OK;
80 }
81
stopStream()82 Return<void> SurroundView3dSession::stopStream() {
83 ALOGD("SurroundView3dSession::stopStream");
84 std::unique_lock <std::mutex> lock(mAccessLock);
85
86 if (mStreamState == RUNNING) {
87 // Tell the GenerateFrames loop we want it to stop
88 mStreamState = STOPPING;
89
90 // Block outside the mutex until the "stop" flag has been acknowledged
91 // We won't send any more frames, but the client might still get some already in flight
92 ALOGD("Waiting for stream thread to end...");
93 lock.unlock();
94 mCaptureThread.join();
95 lock.lock();
96
97 mStreamState = STOPPED;
98 mStream = nullptr;
99 ALOGD("Stream marked STOPPED.");
100 }
101
102 return android::hardware::Void();
103 }
104
doneWithFrames(const SvFramesDesc & svFramesDesc)105 Return<void> SurroundView3dSession::doneWithFrames(
106 const SvFramesDesc& svFramesDesc){
107 ALOGD("SurroundView3dSession::doneWithFrames");
108 std::unique_lock <std::mutex> lock(mAccessLock);
109
110 framesRecord.inUse = false;
111
112 (void)svFramesDesc;
113 return android::hardware::Void();
114 }
115
116 // Methods from ISurroundView3dSession follow.
setViews(const hidl_vec<View3d> & views)117 Return<SvResult> SurroundView3dSession::setViews(const hidl_vec<View3d>& views) {
118 ALOGD("SurroundView3dSession::stopStream");
119 std::unique_lock <std::mutex> lock(mAccessLock);
120
121 mViews.resize(views.size());
122 for (int i=0; i<views.size(); i++) {
123 mViews[i] = views[i];
124 }
125
126 return SvResult::OK;
127 }
128
set3dConfig(const Sv3dConfig & sv3dConfig)129 Return<SvResult> SurroundView3dSession::set3dConfig(const Sv3dConfig& sv3dConfig) {
130 ALOGD("SurroundView3dSession::set3dConfig");
131 std::unique_lock <std::mutex> lock(mAccessLock);
132
133 mConfig.width = sv3dConfig.width;
134 mConfig.height = sv3dConfig.height;
135 mConfig.carDetails = sv3dConfig.carDetails;
136 ALOGD("Notify SvEvent::CONFIG_UPDATED");
137 mStream->notify(SvEvent::CONFIG_UPDATED);
138
139 return SvResult::OK;
140 }
141
get3dConfig(get3dConfig_cb _hidl_cb)142 Return<void> SurroundView3dSession::get3dConfig(get3dConfig_cb _hidl_cb) {
143 ALOGD("SurroundView3dSession::get3dConfig");
144 std::unique_lock <std::mutex> lock(mAccessLock);
145
146 _hidl_cb(mConfig);
147 return android::hardware::Void();
148 }
149
VerifyOverlayData(const OverlaysData & overlaysData)150 bool VerifyOverlayData(const OverlaysData& overlaysData) {
151 // Check size of shared memory matches overlaysMemoryDesc.
152 const int kVertexSize = 16;
153 const int kIdSize = 2;
154 int memDescSize = 0;
155 for (auto overlayMemDesc : overlaysData.overlaysMemoryDesc) {
156 memDescSize += kIdSize + kVertexSize * overlayMemDesc.verticesCount;
157 }
158 if (memDescSize != overlaysData.overlaysMemory.size()) {
159 ALOGE("shared memory and overlaysMemoryDesc size mismatch.");
160 return false;
161 }
162
163 // Map memory.
164 sp<IMemory> pSharedMemory = mapMemory(overlaysData.overlaysMemory);
165 if(pSharedMemory.get() == nullptr) {
166 ALOGE("mapMemory failed.");
167 return false;
168 }
169
170 // Get Data pointer.
171 uint8_t* pData = (uint8_t*)((void*)pSharedMemory->getPointer());
172 if (pData == nullptr) {
173 ALOGE("Shared memory getPointer() failed.");
174 return false;
175 }
176
177 int idOffset = 0;
178 std::set<uint16_t> overlayIdSet;
179 for (auto overlayMemDesc : overlaysData.overlaysMemoryDesc) {
180
181 if (overlayIdSet.find(overlayMemDesc.id) != overlayIdSet.end()) {
182 ALOGE("Duplicate id within memory descriptor.");
183 return false;
184 }
185 overlayIdSet.insert(overlayMemDesc.id);
186
187 if(overlayMemDesc.verticesCount < 3) {
188 ALOGE("Less than 3 vertices.");
189 return false;
190 }
191
192 if (overlayMemDesc.overlayPrimitive == OverlayPrimitive::TRIANGLES &&
193 overlayMemDesc.verticesCount % 3 != 0) {
194 ALOGE("Triangles primitive does not have vertices multiple of 3.");
195 return false;
196 }
197
198 uint16_t overlayId = *((uint16_t*)(pData + idOffset));
199
200 if (overlayId != overlayMemDesc.id) {
201 ALOGE("Overlay id mismatch %d , %d", overlayId, overlayMemDesc.id);
202 return false;
203 }
204
205 idOffset += kIdSize + (kVertexSize * overlayMemDesc.verticesCount);
206 }
207
208 return true;
209 }
210
updateOverlays(const OverlaysData & overlaysData)211 Return<SvResult> SurroundView3dSession::updateOverlays(
212 const OverlaysData& overlaysData) {
213
214 if(!VerifyOverlayData(overlaysData)) {
215 ALOGE("VerifyOverlayData failed.");
216 return SvResult::INVALID_ARG;
217 }
218
219 return SvResult::OK;
220 }
221
projectCameraPointsTo3dSurface(const hidl_vec<Point2dInt> & cameraPoints,const hidl_string & cameraId,projectCameraPointsTo3dSurface_cb _hidl_cb)222 Return<void> SurroundView3dSession::projectCameraPointsTo3dSurface(
223 const hidl_vec<Point2dInt>& cameraPoints,
224 const hidl_string& cameraId,
225 projectCameraPointsTo3dSurface_cb _hidl_cb) {
226
227 std::vector<Point3dFloat> points3d;
228 bool cameraIdFound = false;
229 for (auto evsCameraId : mEvsCameraIds) {
230 if (cameraId == evsCameraId) {
231 cameraIdFound = true;
232 ALOGI("Camera id found.");
233 break;
234 }
235 }
236
237 if (!cameraIdFound) {
238 ALOGE("Camera id not found.");
239 _hidl_cb(points3d);
240 return android::hardware::Void();
241 }
242
243 for (const auto cameraPoint : cameraPoints) {
244 Point3dFloat point3d;
245 point3d.isValid = true;
246
247 if (cameraPoint.x < 0 || cameraPoint.x >= mConfig.width-1 ||
248 cameraPoint.y < 0 || cameraPoint.y >= mConfig.height-1) {
249 ALOGE("Camera point out of bounds.");
250 point3d.isValid = false;
251 }
252 points3d.push_back(point3d);
253 }
254 _hidl_cb(points3d);
255 return android::hardware::Void();
256 }
257
generateFrames()258 void SurroundView3dSession::generateFrames() {
259 ALOGD("SurroundView3dSession::generateFrames");
260
261 int sequenceId = 0;
262
263 while(true) {
264 {
265 std::lock_guard<std::mutex> lock(mAccessLock);
266
267 if (mStreamState != RUNNING) {
268 // Break out of our main thread loop
269 break;
270 }
271 }
272
273 usleep(100 * 1000);
274
275 framesRecord.frames.timestampNs = elapsedRealtimeNano();
276 framesRecord.frames.sequenceId = sequenceId++;
277
278 framesRecord.frames.svBuffers.resize(mViews.size());
279 for (int i=0; i<mViews.size(); i++) {
280 framesRecord.frames.svBuffers[i].viewId = mViews[i].viewId;
281 framesRecord.frames.svBuffers[i].hardwareBuffer.nativeHandle = new native_handle_t();
282 framesRecord.frames.svBuffers[i].hardwareBuffer.description[0] = mConfig.width; // width
283 framesRecord.frames.svBuffers[i].hardwareBuffer.description[1] = mConfig.height; // height
284 }
285
286 {
287 std::lock_guard<std::mutex> lock(mAccessLock);
288
289 if (framesRecord.inUse) {
290 ALOGD("Notify SvEvent::FRAME_DROPPED");
291 mStream->notify(SvEvent::FRAME_DROPPED);
292 } else {
293 framesRecord.inUse = true;
294 mStream->receiveFrames(framesRecord.frames);
295 }
296 }
297 }
298
299 // If we've been asked to stop, send an event to signal the actual end of stream
300 ALOGD("Notify SvEvent::STREAM_STOPPED");
301 mStream->notify(SvEvent::STREAM_STOPPED);
302 }
303
304 } // namespace implementation
305 } // namespace V1_0
306 } // namespace sv
307 } // namespace automotive
308 } // namespace hardware
309 } // namespace android
310
311