1 // Copyright 2020 The Android Open Source Project
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 #include "EvsInputManager.h"
15
16 #include <chrono>
17 #include <map>
18 #include <shared_mutex>
19 #include <string>
20 #include <thread>
21
22 #include "AnalyzeUseCase.h"
23 #include "BaseAnalyzeCallback.h"
24 #include "InputConfig.pb.h"
25 #include "InputEngineInterface.h"
26 #include "Options.pb.h"
27
28 using ::android::automotive::evs::support::AnalyzeUseCase;
29 using ::android::automotive::evs::support::BaseAnalyzeCallback;
30
31 namespace android {
32 namespace automotive {
33 namespace computepipe {
34 namespace runner {
35 namespace input_manager {
36
analyze(const::android::automotive::evs::support::Frame & frame)37 void AnalyzeCallback::analyze(const ::android::automotive::evs::support::Frame& frame) {
38 std::shared_lock lock(mEngineInterfaceLock);
39 if (mInputEngineInterface != nullptr) {
40 auto time_point = std::chrono::system_clock::now();
41 int64_t timestamp = std::chrono::time_point_cast<std::chrono::microseconds>(time_point)
42 .time_since_epoch()
43 .count();
44 // Stride for hardware buffers is specified in pixels whereas for
45 // InputFrame, it is specified in bytes. We therefore need to multiply
46 // the stride by 4 for an RGBA frame.
47 InputFrame inputFrame(frame.height, frame.width, PixelFormat::RGBA, frame.stride * 4,
48 frame.data);
49 mInputEngineInterface->dispatchInputFrame(mInputStreamId, timestamp, inputFrame);
50 }
51 }
52
setEngineInterface(std::shared_ptr<InputEngineInterface> inputEngineInterface)53 void AnalyzeCallback::setEngineInterface(std::shared_ptr<InputEngineInterface> inputEngineInterface) {
54 std::lock_guard lock(mEngineInterfaceLock);
55 mInputEngineInterface = inputEngineInterface;
56 }
57
EvsInputManager(const proto::InputConfig & inputConfig,std::shared_ptr<InputEngineInterface> inputEngineInterface)58 EvsInputManager::EvsInputManager(const proto::InputConfig& inputConfig,
59 std::shared_ptr<InputEngineInterface> inputEngineInterface)
60 : mInputEngineInterface(inputEngineInterface), mInputConfig(inputConfig) {
61 }
62
createEvsInputManager(const proto::InputConfig & inputConfig,std::shared_ptr<InputEngineInterface> inputEngineInterface)63 std::unique_ptr<EvsInputManager> EvsInputManager::createEvsInputManager(
64 const proto::InputConfig& inputConfig,
65 std::shared_ptr<InputEngineInterface> inputEngineInterface) {
66 auto evsManager = std::make_unique<EvsInputManager>(inputConfig, inputEngineInterface);
67 if (evsManager->initializeCameras() == Status::SUCCESS) {
68 return evsManager;
69 }
70
71 return nullptr;
72 }
73
initializeCameras()74 Status EvsInputManager::initializeCameras() {
75 for (int i = 0; i < mInputConfig.input_stream_size(); i++) {
76 // Verify that the stream type specified is a camera stream which is necessary for evs
77 // manager.
78 if (mInputConfig.input_stream(i).type() != proto::InputStreamConfig_InputType_CAMERA) {
79 ALOGE("Evs stream manager expects the input stream type to be camera.");
80 return Status::INVALID_ARGUMENT;
81 }
82 const std::string& cameraId = mInputConfig.input_stream(i).cam_config().cam_id();
83 std::unique_ptr<AnalyzeCallback> analyzeCallback =
84 std::make_unique<AnalyzeCallback>(mInputConfig.input_stream(i).stream_id());
85 AnalyzeUseCase analyzeUseCase =
86 AnalyzeUseCase::createDefaultUseCase(cameraId, analyzeCallback.get());
87 mAnalyzeCallbacks.push_back(std::move(analyzeCallback));
88
89 int streamId = mInputConfig.input_stream(i).stream_id();
90 auto [it, result] = mEvsUseCases.try_emplace(std::move(streamId),
91 std::move(analyzeUseCase));
92 if (!result) {
93 // Multiple camera streams found to have the same camera id.
94 ALOGE("Multiple camera streams have the same stream id.");
95 return Status::INVALID_ARGUMENT;
96 }
97 }
98
99 return Status::SUCCESS;
100 }
101
handleExecutionPhase(const RunnerEvent & e)102 Status EvsInputManager::handleExecutionPhase(const RunnerEvent& e) {
103 // Starting execution cannot be stopped in between. handleStopImmediate needs to be called.
104 if (e.isAborted()) {
105 return Status::INVALID_ARGUMENT;
106 } else if (e.isTransitionComplete()) {
107 return Status::SUCCESS;
108 }
109
110 if (mEvsUseCases.empty()) {
111 ALOGE("No evs use cases configured. Verify that handleConfigPhase has been called");
112 return Status::ILLEGAL_STATE;
113 }
114
115 // Start all the video streams.
116 bool successfullyStartedAllCameras = true;
117 for (auto& [streamId, evsUseCase] : mEvsUseCases) {
118 if (!evsUseCase.startVideoStream()) {
119 successfullyStartedAllCameras = false;
120 ALOGE("Unable to successfully start all cameras");
121 break;
122 }
123 }
124
125 // If not all video streams have started successfully, stop the streams.
126 if (!successfullyStartedAllCameras) {
127 for (auto& [streamId, evsUseCase] : mEvsUseCases) {
128 evsUseCase.stopVideoStream();
129 }
130 return Status::INTERNAL_ERROR;
131 }
132
133 // Set the input to engine interface for callbacks only when all the streams have successfully
134 // started. This prevents any callback from going out unless all of the streams have started.
135 for (auto& analyzeCallback : mAnalyzeCallbacks) {
136 analyzeCallback->setEngineInterface(mInputEngineInterface);
137 }
138
139 return Status::SUCCESS;
140 }
141
handleStopImmediatePhase(const RunnerEvent & e)142 Status EvsInputManager::handleStopImmediatePhase(const RunnerEvent& e) {
143 if (e.isAborted()) {
144 ALOGE(
145 "Unable to abort immediate stopping of EVS cameras. Please start the video streams "
146 "again if "
147 "needed.");
148 } else if (e.isTransitionComplete()) {
149 return Status::SUCCESS;
150 }
151
152 // Reset all input engine interfaces so that callbacks stop going out even if there are evs
153 // frames in flux.
154 for (auto& analyzeCallback : mAnalyzeCallbacks) {
155 analyzeCallback->setEngineInterface(nullptr);
156 }
157
158 for (auto& [streamId, evsUseCase] : mEvsUseCases) {
159 evsUseCase.stopVideoStream();
160 }
161
162 return Status::SUCCESS;
163 }
164
handleStopWithFlushPhase(const RunnerEvent & e)165 Status EvsInputManager::handleStopWithFlushPhase(const RunnerEvent& e) {
166 if (e.isAborted()) {
167 ALOGE(
168 "Unable to abort stopping and flushing of EVS cameras. Please start the video streams "
169 "again if "
170 "needed.");
171 } else if (e.isTransitionComplete()) {
172 return Status::SUCCESS;
173 }
174
175 for (auto& [streamId, evsUseCase] : mEvsUseCases) {
176 evsUseCase.stopVideoStream();
177 }
178 return Status::SUCCESS;
179 }
180
handleResetPhase(const RunnerEvent & e)181 Status EvsInputManager::handleResetPhase(const RunnerEvent& e) {
182 if (e.isAborted()) {
183 ALOGE("Unable to abort reset.");
184 return Status::INVALID_ARGUMENT;
185 }
186 mEvsUseCases.clear();
187 mAnalyzeCallbacks.clear();
188 return Status::SUCCESS;
189 }
190
191 } // namespace input_manager
192 } // namespace runner
193 } // namespace computepipe
194 } // namespace automotive
195 } // namespace android
196