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 "SurroundView2dSession.h"
18
19 #include <utils/Log.h>
20 #include <utils/SystemClock.h>
21
22 namespace android {
23 namespace hardware {
24 namespace automotive {
25 namespace sv {
26 namespace V1_0 {
27 namespace implementation {
28
SurroundView2dSession()29 SurroundView2dSession::SurroundView2dSession() :
30 mStreamState(STOPPED) {
31 mEvsCameraIds = {"0" , "1", "2", "3"};
32
33 mConfig.width = 640;
34 mConfig.blending = SvQuality::HIGH;
35
36 framesRecord.frames.svBuffers.resize(1);
37 framesRecord.frames.svBuffers[0].viewId = 0;
38 framesRecord.frames.svBuffers[0].hardwareBuffer.nativeHandle =
39 new native_handle_t();
40 framesRecord.frames.svBuffers[0].hardwareBuffer.description[0] =
41 mConfig.width;
42 framesRecord.frames.svBuffers[0].hardwareBuffer.description[1] =
43 mConfig.width * 3 / 4;
44 }
45
46 // Methods from ::android::hardware::automotive::sv::V1_0::ISurroundViewSession
startStream(const sp<ISurroundViewStream> & stream)47 Return<SvResult> SurroundView2dSession::startStream(
48 const sp<ISurroundViewStream>& stream) {
49 ALOGD("SurroundView2dSession::startStream");
50 std::lock_guard<std::mutex> lock(mAccessLock);
51
52 if (mStreamState != STOPPED) {
53 ALOGE("ignoring startVideoStream call"
54 "when a stream is already running.");
55 return SvResult::INTERNAL_ERROR;
56 }
57
58 mStream = stream;
59
60 ALOGD("Notify SvEvent::STREAM_STARTED");
61 mStream->notify(SvEvent::STREAM_STARTED);
62
63 // Start the frame generation thread
64 mStreamState = RUNNING;
65 mCaptureThread = std::thread([this](){ generateFrames(); });
66
67 return SvResult::OK;
68 }
69
stopStream()70 Return<void> SurroundView2dSession::stopStream() {
71 ALOGD("SurroundView2dSession::stopStream");
72 std::unique_lock <std::mutex> lock(mAccessLock);
73
74 if (mStreamState == RUNNING) {
75 // Tell the GenerateFrames loop we want it to stop
76 mStreamState = STOPPING;
77
78 // Block outside the mutex until the "stop" flag has been acknowledged
79 // We won't send any more frames, but the client might still get some
80 // already in flight
81 ALOGD("Waiting for stream thread to end...");
82 lock.unlock();
83 mCaptureThread.join();
84 lock.lock();
85
86 mStreamState = STOPPED;
87 mStream = nullptr;
88 ALOGD("Stream marked STOPPED.");
89 }
90
91 return android::hardware::Void();
92 }
93
doneWithFrames(const SvFramesDesc & svFramesDesc)94 Return<void> SurroundView2dSession::doneWithFrames(
95 const SvFramesDesc& svFramesDesc){
96 ALOGD("SurroundView2dSession::doneWithFrames");
97 std::unique_lock <std::mutex> lock(mAccessLock);
98
99 framesRecord.inUse = false;
100
101 (void)svFramesDesc;
102 return android::hardware::Void();
103 }
104
105 // Methods from ISurroundView2dSession follow.
get2dMappingInfo(get2dMappingInfo_cb _hidl_cb)106 Return<void> SurroundView2dSession::get2dMappingInfo(
107 get2dMappingInfo_cb _hidl_cb) {
108 ALOGD("SurroundView2dSession::get2dMappingInfo");
109 std::unique_lock <std::mutex> lock(mAccessLock);
110
111 Sv2dMappingInfo info;
112 info.width = 8; // keeps ratio to 4:3
113 info.height = 6;
114 info.center.isValid = true;
115 info.center.x = 0;
116 info.center.y = 0;
117 _hidl_cb(info);
118 return android::hardware::Void();
119 }
120
set2dConfig(const Sv2dConfig & sv2dConfig)121 Return<SvResult> SurroundView2dSession::set2dConfig(
122 const Sv2dConfig& sv2dConfig) {
123 ALOGD("SurroundView2dSession::setConfig");
124 std::unique_lock <std::mutex> lock(mAccessLock);
125
126 mConfig.width = sv2dConfig.width;
127 mConfig.blending = sv2dConfig.blending;
128 ALOGD("Notify SvEvent::CONFIG_UPDATED");
129 mStream->notify(SvEvent::CONFIG_UPDATED);
130
131 return SvResult::OK;
132 }
133
get2dConfig(get2dConfig_cb _hidl_cb)134 Return<void> SurroundView2dSession::get2dConfig(get2dConfig_cb _hidl_cb) {
135 ALOGD("SurroundView2dSession::getConfig");
136 std::unique_lock <std::mutex> lock(mAccessLock);
137
138 _hidl_cb(mConfig);
139 return android::hardware::Void();
140 }
141
projectCameraPoints(const hidl_vec<Point2dInt> & points2dCamera,const hidl_string & cameraId,projectCameraPoints_cb _hidl_cb)142 Return<void> SurroundView2dSession::projectCameraPoints(
143 const hidl_vec<Point2dInt>& points2dCamera,
144 const hidl_string& cameraId,
145 projectCameraPoints_cb _hidl_cb) {
146 ALOGD("SurroundView2dSession::projectCameraPoints");
147 std::unique_lock <std::mutex> lock(mAccessLock);
148
149 bool cameraIdFound = false;
150 for (auto evsCameraId : mEvsCameraIds) {
151 if (cameraId == evsCameraId) {
152 cameraIdFound = true;
153 ALOGI("Camera id found.");
154 break;
155 }
156 }
157
158 if (!cameraIdFound) {
159 ALOGE("Camera id not found.");
160 _hidl_cb(hidl_vec<Point2dFloat>());
161 return android::hardware::Void();
162 }
163
164 hidl_vec<Point2dFloat> outPoints;
165 outPoints.resize(points2dCamera.size());
166
167 int width = mConfig.width;
168 int height = mConfig.width * 3 / 4;
169 for (int i=0; i<points2dCamera.size(); i++) {
170 // Assuming all the points in the image frame can be projected into 2d
171 // Surround View space. Otherwise cannot.
172 if (points2dCamera[i].x < 0 || points2dCamera[i].y > width-1 ||
173 points2dCamera[i].x < 0 || points2dCamera[i].y > height-1) {
174 ALOGW("SurroundView2dSession::projectCameraPoints "
175 "gets invalid 2d camera points. Ignored");
176 outPoints[i].isValid = false;
177 outPoints[i].x = 10000;
178 outPoints[i].y = 10000;
179 } else {
180 outPoints[i].isValid = true;
181 outPoints[i].x = 0;
182 outPoints[i].y = 0;
183 }
184 }
185
186 _hidl_cb(outPoints);
187 return android::hardware::Void();
188 }
189
generateFrames()190 void SurroundView2dSession::generateFrames() {
191 ALOGD("SurroundView2dSession::generateFrames");
192
193 int sequenceId = 0;
194
195 while(true) {
196 {
197 std::lock_guard<std::mutex> lock(mAccessLock);
198
199 if (mStreamState != RUNNING) {
200 // Break out of our main thread loop
201 break;
202 }
203
204 framesRecord.frames.svBuffers[0].hardwareBuffer.description[0] =
205 mConfig.width;
206 framesRecord.frames.svBuffers[0].hardwareBuffer.description[1] =
207 mConfig.width * 3 / 4;
208 }
209
210 usleep(100 * 1000);
211
212 framesRecord.frames.timestampNs = elapsedRealtimeNano();
213 framesRecord.frames.sequenceId = sequenceId++;
214
215 {
216 std::lock_guard<std::mutex> lock(mAccessLock);
217
218 if (framesRecord.inUse) {
219 ALOGD("Notify SvEvent::FRAME_DROPPED");
220 mStream->notify(SvEvent::FRAME_DROPPED);
221 } else {
222 framesRecord.inUse = true;
223 mStream->receiveFrames(framesRecord.frames);
224 }
225 }
226 }
227
228 // If we've been asked to stop, send an event to signal the actual
229 // end of stream
230 ALOGD("Notify SvEvent::STREAM_STOPPED");
231 mStream->notify(SvEvent::STREAM_STOPPED);
232 }
233
234 } // namespace implementation
235 } // namespace V1_0
236 } // namespace sv
237 } // namespace automotive
238 } // namespace hardware
239 } // namespace android
240
241