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