blob: c5b7894c8635725438c464982ae5b8f0feec57ad [file] [log] [blame]
Haoxiang Li35d2a702020-04-10 01:19:32 +00001/*
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#define LOG_TAG "SurroundViewService"
17
Haoxiang Lib88cd3e2020-06-04 10:27:31 -070018#include "SurroundView2dSession.h"
19
Haoxiang Li35d2a702020-04-10 01:19:32 +000020#include <android-base/logging.h>
21#include <android/hardware_buffer.h>
Haoxiang Lib88cd3e2020-06-04 10:27:31 -070022#include <system/camera_metadata.h>
Haoxiang Li35d2a702020-04-10 01:19:32 +000023#include <utils/SystemClock.h>
24
Haoxiang Lib88cd3e2020-06-04 10:27:31 -070025#include <thread>
Haoxiang Li35d2a702020-04-10 01:19:32 +000026
Haoxiang Lib88cd3e2020-06-04 10:27:31 -070027#include <android/hardware/camera/device/3.2/ICameraDevice.h>
28
Haoxiang Li0c078242020-06-10 16:59:29 -070029#include "CameraUtils.h"
30
Haoxiang Lib88cd3e2020-06-04 10:27:31 -070031using ::android::hardware::automotive::evs::V1_0::EvsResult;
32using ::android::hardware::camera::device::V3_2::Stream;
33
34using GraphicsPixelFormat = ::android::hardware::graphics::common::V1_0::PixelFormat;
Haoxiang Li35d2a702020-04-10 01:19:32 +000035
36namespace android {
37namespace hardware {
38namespace automotive {
39namespace sv {
40namespace V1_0 {
41namespace implementation {
42
Haoxiang Lib88cd3e2020-06-04 10:27:31 -070043// TODO(b/158479099): There are a lot of redundant code between 2d and 3d.
44// Decrease the degree of redundancy.
45typedef struct {
46 int32_t id;
47 int32_t width;
48 int32_t height;
49 int32_t format;
50 int32_t direction;
51 int32_t framerate;
52} RawStreamConfig;
53
54static const size_t kStreamCfgSz = sizeof(RawStreamConfig);
Haoxiang Lia4d8de42020-04-10 01:19:32 +000055static const uint8_t kGrayColor = 128;
Haoxiang Li35d2a702020-04-10 01:19:32 +000056static const int kNumChannels = 3;
Haoxiang Lia091e4a2020-06-06 20:38:46 -070057static const int kNumFrames = 4;
Haoxiang Lica7719a2020-06-03 20:51:11 -070058static const int kSv2dViewId = 0;
59
Haoxiang Lib88cd3e2020-06-04 10:27:31 -070060SurroundView2dSession::FramesHandler::FramesHandler(
61 sp<IEvsCamera> pCamera, sp<SurroundView2dSession> pSession)
62 : mCamera(pCamera),
63 mSession(pSession) {}
64
65Return<void> SurroundView2dSession::FramesHandler::deliverFrame(
66 const BufferDesc_1_0& bufDesc_1_0) {
67 LOG(INFO) << "Ignores a frame delivered from v1.0 EVS service.";
68 mCamera->doneWithFrame(bufDesc_1_0);
69
Haoxiang Lia091e4a2020-06-06 20:38:46 -070070 return {};
Haoxiang Lib88cd3e2020-06-04 10:27:31 -070071}
72
73Return<void> SurroundView2dSession::FramesHandler::deliverFrame_1_1(
74 const hidl_vec<BufferDesc_1_1>& buffers) {
75 LOG(INFO) << "Received " << buffers.size() << " frames from the camera";
76 mSession->mSequenceId++;
77
Haoxiang Lie3011cc2020-06-10 21:33:26 -070078 {
79 scoped_lock<mutex> lock(mSession->mAccessLock);
80 if (mSession->mProcessingEvsFrames) {
81 LOG(WARNING) << "EVS frames are being processed. Skip frames:" << mSession->mSequenceId;
82 mCamera->doneWithFrame_1_1(buffers);
83 return {};
84 }
85 }
86
Haoxiang Lia091e4a2020-06-06 20:38:46 -070087 if (buffers.size() != kNumFrames) {
88 LOG(ERROR) << "The number of incoming frames is " << buffers.size()
89 << ", which is different from the number " << kNumFrames
90 << ", specified in config file";
91 return {};
92 }
93
94 {
95 scoped_lock<mutex> lock(mSession->mAccessLock);
96 for (int i = 0; i < kNumFrames; i++) {
97 LOG(DEBUG) << "Copying buffer No." << i
98 << " to Surround View Service";
99 mSession->copyFromBufferToPointers(buffers[i],
100 mSession->mInputPointers[i]);
101 }
102 }
103
Haoxiang Lib88cd3e2020-06-04 10:27:31 -0700104 mCamera->doneWithFrame_1_1(buffers);
105
106 // Notify the session that a new set of frames is ready
107 {
108 scoped_lock<mutex> lock(mSession->mAccessLock);
Haoxiang Lie3011cc2020-06-10 21:33:26 -0700109 mSession->mProcessingEvsFrames = true;
Haoxiang Lib88cd3e2020-06-04 10:27:31 -0700110 }
111 mSession->mFramesSignal.notify_all();
112
Haoxiang Lia091e4a2020-06-06 20:38:46 -0700113 return {};
Haoxiang Lib88cd3e2020-06-04 10:27:31 -0700114}
115
116Return<void> SurroundView2dSession::FramesHandler::notify(const EvsEventDesc& event) {
117 switch(event.aType) {
118 case EvsEventType::STREAM_STOPPED:
119 {
120 LOG(INFO) << "Received a STREAM_STOPPED event from Evs.";
121
122 // TODO(b/158339680): There is currently an issue in EVS reference
123 // implementation that causes STREAM_STOPPED event to be delivered
124 // properly. When the bug is fixed, we should deal with this event
125 // properly in case the EVS stream is stopped unexpectly.
126 break;
127 }
128
129 case EvsEventType::PARAMETER_CHANGED:
130 LOG(INFO) << "Camera parameter " << std::hex << event.payload[0]
131 << " is set to " << event.payload[1];
132 break;
133
134 // Below events are ignored in reference implementation.
135 case EvsEventType::STREAM_STARTED:
136 [[fallthrough]];
137 case EvsEventType::FRAME_DROPPED:
138 [[fallthrough]];
139 case EvsEventType::TIMEOUT:
140 LOG(INFO) << "Event " << std::hex << static_cast<unsigned>(event.aType)
141 << "is received but ignored.";
142 break;
143 default:
144 LOG(ERROR) << "Unknown event id: " << static_cast<unsigned>(event.aType);
145 break;
146 }
147
Haoxiang Lia091e4a2020-06-06 20:38:46 -0700148 return {};
149}
150
151bool SurroundView2dSession::copyFromBufferToPointers(
152 BufferDesc_1_1 buffer, SurroundViewInputBufferPointers pointers) {
153
154 AHardwareBuffer_Desc* pDesc =
155 reinterpret_cast<AHardwareBuffer_Desc *>(&buffer.buffer.description);
156
157 // create a GraphicBuffer from the existing handle
158 sp<GraphicBuffer> inputBuffer = new GraphicBuffer(
159 buffer.buffer.nativeHandle, GraphicBuffer::CLONE_HANDLE, pDesc->width,
160 pDesc->height, pDesc->format, pDesc->layers,
161 GRALLOC_USAGE_HW_TEXTURE, pDesc->stride);
162
163 if (inputBuffer == nullptr) {
164 LOG(ERROR) << "Failed to allocate GraphicBuffer to wrap image handle";
165 // Returning "true" in this error condition because we already released the
166 // previous image (if any) and so the texture may change in unpredictable
167 // ways now!
168 return false;
169 } else {
170 LOG(INFO) << "Managed to allocate GraphicBuffer with "
171 << " width: " << pDesc->width
172 << " height: " << pDesc->height
173 << " format: " << pDesc->format
174 << " stride: " << pDesc->stride;
175 }
176
177 // Lock the input GraphicBuffer and map it to a pointer. If we failed to
178 // lock, return false.
179 void* inputDataPtr;
180 inputBuffer->lock(
181 GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_NEVER,
182 &inputDataPtr);
183 if (!inputDataPtr) {
184 LOG(ERROR) << "Failed to gain read access to GraphicBuffer";
185 inputBuffer->unlock();
186 return false;
187 } else {
188 LOG(INFO) << "Managed to get read access to GraphicBuffer";
189 }
190
191 int stride = pDesc->stride;
192
193 // readPtr comes from EVS, and it is with 4 channels
194 uint8_t* readPtr = static_cast<uint8_t*>(inputDataPtr);
195
196 // writePtr comes from CV imread, and it is with 3 channels
197 uint8_t* writePtr = static_cast<uint8_t*>(pointers.cpu_data_pointer);
198
199 for (int i=0; i<pDesc->width; i++)
200 for (int j=0; j<pDesc->height; j++) {
201 writePtr[(i + j * stride) * 3 + 0] =
202 readPtr[(i + j * stride) * 4 + 0];
203 writePtr[(i + j * stride) * 3 + 1] =
204 readPtr[(i + j * stride) * 4 + 1];
205 writePtr[(i + j * stride) * 3 + 2] =
206 readPtr[(i + j * stride) * 4 + 2];
207 }
208 LOG(INFO) << "Brute force copying finished";
209
210 return true;
Haoxiang Lib88cd3e2020-06-04 10:27:31 -0700211}
212
Haoxiang Lica7719a2020-06-03 20:51:11 -0700213void SurroundView2dSession::processFrames() {
214 while (true) {
215 {
216 unique_lock<mutex> lock(mAccessLock);
217
218 if (mStreamState != RUNNING) {
219 break;
220 }
221
Haoxiang Lie3011cc2020-06-10 21:33:26 -0700222 mFramesSignal.wait(lock, [this]() { return mProcessingEvsFrames; });
Haoxiang Lica7719a2020-06-03 20:51:11 -0700223 }
224
225 handleFrames(mSequenceId);
226
227 {
228 // Set the boolean to false to receive the next set of frames.
Haoxiang Lib88cd3e2020-06-04 10:27:31 -0700229 scoped_lock<mutex> lock(mAccessLock);
Haoxiang Lie3011cc2020-06-10 21:33:26 -0700230 mProcessingEvsFrames = false;
Haoxiang Lica7719a2020-06-03 20:51:11 -0700231 }
232 }
Haoxiang Lib88cd3e2020-06-04 10:27:31 -0700233
234 // Notify the SV client that no new results will be delivered.
235 LOG(DEBUG) << "Notify SvEvent::STREAM_STOPPED";
236 mStream->notify(SvEvent::STREAM_STOPPED);
237
238 {
239 scoped_lock<mutex> lock(mAccessLock);
240 mStreamState = STOPPED;
241 mStream = nullptr;
242 LOG(DEBUG) << "Stream marked STOPPED.";
243 }
Haoxiang Lica7719a2020-06-03 20:51:11 -0700244}
Haoxiang Li35d2a702020-04-10 01:19:32 +0000245
Haoxiang Lif7120b42020-06-12 12:45:36 -0700246SurroundView2dSession::SurroundView2dSession(sp<IEvsEnumerator> pEvs,
247 IOModuleConfig* pConfig)
Haoxiang Lib88cd3e2020-06-04 10:27:31 -0700248 : mEvs(pEvs),
Haoxiang Lif7120b42020-06-12 12:45:36 -0700249 mIOModuleConfig(pConfig),
Haoxiang Lib88cd3e2020-06-04 10:27:31 -0700250 mStreamState(STOPPED) {
Haoxiang Li35d2a702020-04-10 01:19:32 +0000251 mEvsCameraIds = {"0", "1", "2", "3"};
252}
253
Haoxiang Lib88cd3e2020-06-04 10:27:31 -0700254SurroundView2dSession::~SurroundView2dSession() {
255 // In case the client did not call stopStream properly, we should stop the
256 // stream explicitly. Otherwise the process thread will take forever to
257 // join.
258 stopStream();
259
260 // Waiting for the process thread to finish the buffered frames.
261 if (mProcessThread.joinable()) {
262 mProcessThread.join();
263 }
264
265 mEvs->closeCamera(mCamera);
266}
267
Haoxiang Li35d2a702020-04-10 01:19:32 +0000268// Methods from ::android::hardware::automotive::sv::V1_0::ISurroundViewSession
269Return<SvResult> SurroundView2dSession::startStream(
270 const sp<ISurroundViewStream>& stream) {
271 LOG(DEBUG) << __FUNCTION__;
272 scoped_lock<mutex> lock(mAccessLock);
273
274 if (!mIsInitialized && !initialize()) {
275 LOG(ERROR) << "There is an error while initializing the use case. "
276 << "Exiting";
277 return SvResult::INTERNAL_ERROR;
278 }
279
280 if (mStreamState != STOPPED) {
281 LOG(ERROR) << "Ignoring startVideoStream call"
282 << "when a stream is already running.";
283 return SvResult::INTERNAL_ERROR;
284 }
285
286 if (stream == nullptr) {
287 LOG(ERROR) << "The input stream is invalid";
288 return SvResult::INTERNAL_ERROR;
289 }
290 mStream = stream;
291
Haoxiang Lib88cd3e2020-06-04 10:27:31 -0700292 mSequenceId = 0;
293 startEvs();
294
295 // TODO(b/158131080): the STREAM_STARTED event is not implemented in EVS
296 // reference implementation yet. Once implemented, this logic should be
297 // moved to EVS notify callback.
Haoxiang Li35d2a702020-04-10 01:19:32 +0000298 LOG(DEBUG) << "Notify SvEvent::STREAM_STARTED";
299 mStream->notify(SvEvent::STREAM_STARTED);
Haoxiang Lie3011cc2020-06-10 21:33:26 -0700300 mProcessingEvsFrames = false;
Haoxiang Li35d2a702020-04-10 01:19:32 +0000301
302 // Start the frame generation thread
303 mStreamState = RUNNING;
Haoxiang Li35d2a702020-04-10 01:19:32 +0000304
Haoxiang Lica7719a2020-06-03 20:51:11 -0700305 mProcessThread = thread([this]() {
306 processFrames();
307 });
308
Haoxiang Li35d2a702020-04-10 01:19:32 +0000309 return SvResult::OK;
310}
311
312Return<void> SurroundView2dSession::stopStream() {
313 LOG(DEBUG) << __FUNCTION__;
314 unique_lock<mutex> lock(mAccessLock);
315
316 if (mStreamState == RUNNING) {
Haoxiang Lib88cd3e2020-06-04 10:27:31 -0700317 // Tell the processFrames loop to stop processing frames
Haoxiang Li35d2a702020-04-10 01:19:32 +0000318 mStreamState = STOPPING;
319
Haoxiang Lib88cd3e2020-06-04 10:27:31 -0700320 // Stop the EVS stream asynchronizely
321 mCamera->stopVideoStream();
322 mFramesHandler = nullptr;
Haoxiang Li35d2a702020-04-10 01:19:32 +0000323 }
324
325 return {};
326}
327
328Return<void> SurroundView2dSession::doneWithFrames(
329 const SvFramesDesc& svFramesDesc){
330 LOG(DEBUG) << __FUNCTION__;
331 scoped_lock <mutex> lock(mAccessLock);
332
Haoxiang Lie3011cc2020-06-10 21:33:26 -0700333 mFramesRecord.inUse = false;
Haoxiang Li35d2a702020-04-10 01:19:32 +0000334
335 (void)svFramesDesc;
336 return {};
337}
338
339// Methods from ISurroundView2dSession follow.
340Return<void> SurroundView2dSession::get2dMappingInfo(
341 get2dMappingInfo_cb _hidl_cb) {
342 LOG(DEBUG) << __FUNCTION__;
343
344 _hidl_cb(mInfo);
345 return {};
346}
347
348Return<SvResult> SurroundView2dSession::set2dConfig(
349 const Sv2dConfig& sv2dConfig) {
350 LOG(DEBUG) << __FUNCTION__;
351 scoped_lock <mutex> lock(mAccessLock);
352
353 if (sv2dConfig.width <=0 || sv2dConfig.width > 4096) {
354 LOG(WARNING) << "The width of 2d config is out of the range (0, 4096]"
355 << "Ignored!";
356 return SvResult::INVALID_ARG;
357 }
358
359 mConfig.width = sv2dConfig.width;
360 mConfig.blending = sv2dConfig.blending;
361 mHeight = mConfig.width * mInfo.height / mInfo.width;
362
363 if (mStream != nullptr) {
364 LOG(DEBUG) << "Notify SvEvent::CONFIG_UPDATED";
365 mStream->notify(SvEvent::CONFIG_UPDATED);
366 }
367
368 return SvResult::OK;
369}
370
371Return<void> SurroundView2dSession::get2dConfig(get2dConfig_cb _hidl_cb) {
372 LOG(DEBUG) << __FUNCTION__;
373
374 _hidl_cb(mConfig);
375 return {};
376}
377
Tanmay Patil6a85c0e2020-06-14 15:33:39 -0700378Return<void> SurroundView2dSession::projectCameraPoints(const hidl_vec<Point2dInt>& points2dCamera,
379 const hidl_string& cameraId,
380 projectCameraPoints_cb _hidl_cb) {
Haoxiang Li35d2a702020-04-10 01:19:32 +0000381 LOG(DEBUG) << __FUNCTION__;
Tanmay Patil6a85c0e2020-06-14 15:33:39 -0700382 std::vector<Point2dFloat> outPoints;
Haoxiang Li35d2a702020-04-10 01:19:32 +0000383 bool cameraIdFound = false;
Tanmay Patil6a85c0e2020-06-14 15:33:39 -0700384 int cameraIndex = 0;
385 // Note: mEvsCameraIds must be in the order front, right, rear, left.
Haoxiang Li35d2a702020-04-10 01:19:32 +0000386 for (auto& evsCameraId : mEvsCameraIds) {
Tanmay Patil6a85c0e2020-06-14 15:33:39 -0700387 if (cameraId == evsCameraId) {
388 cameraIdFound = true;
389 LOG(DEBUG) << "Camera id found for projection: " << cameraId;
390 break;
391 }
392 cameraIndex++;
Haoxiang Li35d2a702020-04-10 01:19:32 +0000393 }
394
395 if (!cameraIdFound) {
Tanmay Patil6a85c0e2020-06-14 15:33:39 -0700396 LOG(ERROR) << "Camera id not found for projection: " << cameraId;
397 _hidl_cb(outPoints);
Haoxiang Li35d2a702020-04-10 01:19:32 +0000398 return {};
399 }
400
Haoxiang Li35d2a702020-04-10 01:19:32 +0000401 int width = mConfig.width;
402 int height = mHeight;
Tanmay Patil6a85c0e2020-06-14 15:33:39 -0700403 for (const auto& cameraPoint : points2dCamera) {
404 Point2dFloat outPoint = {false, 0.0, 0.0};
405 // Check of the camear point is within the camera resolution bounds.
406 if (cameraPoint.x < 0 || cameraPoint.x > width - 1 || cameraPoint.y < 0 ||
407 cameraPoint.y > height - 1) {
408 LOG(WARNING) << "Camera point (" << cameraPoint.x << ", " << cameraPoint.y
409 << ") is out of camera resolution bounds.";
410 outPoint.isValid = false;
411 outPoints.push_back(outPoint);
412 continue;
Haoxiang Li35d2a702020-04-10 01:19:32 +0000413 }
Tanmay Patil6a85c0e2020-06-14 15:33:39 -0700414
415 // Project points using mSurroundView function.
416 const Coordinate2dInteger camPoint(cameraPoint.x, cameraPoint.y);
417 Coordinate2dFloat projPoint2d(0.0, 0.0);
418
419 outPoint.isValid =
420 mSurroundView->GetProjectionPointFromRawCameraToSurroundView2d(camPoint,
421 cameraIndex,
422 &projPoint2d);
423 outPoint.x = projPoint2d.x;
424 outPoint.y = projPoint2d.y;
425 outPoints.push_back(outPoint);
Haoxiang Li35d2a702020-04-10 01:19:32 +0000426 }
427
428 _hidl_cb(outPoints);
429 return {};
430}
431
Haoxiang Lica7719a2020-06-03 20:51:11 -0700432bool SurroundView2dSession::handleFrames(int sequenceId) {
433 LOG(INFO) << __FUNCTION__ << "Handling sequenceId " << sequenceId << ".";
434
Haoxiang Lie3011cc2020-06-10 21:33:26 -0700435 // TODO(b/157498592): Now only one sets of EVS input frames and one SV
436 // output frame is supported. Implement buffer queue for both of them.
437 {
438 scoped_lock<mutex> lock(mAccessLock);
439
440 if (mFramesRecord.inUse) {
441 LOG(DEBUG) << "Notify SvEvent::FRAME_DROPPED";
442 mStream->notify(SvEvent::FRAME_DROPPED);
443 return true;
444 }
445 }
446
Haoxiang Lib88cd3e2020-06-04 10:27:31 -0700447 if (mOutputWidth != mConfig.width || mOutputHeight != mHeight) {
448 LOG(DEBUG) << "Config changed. Re-allocate memory."
449 << " Old width: "
450 << mOutputWidth
451 << " Old height: "
452 << mOutputHeight
453 << " New width: "
454 << mConfig.width
455 << " New height: "
456 << mHeight;
457 delete[] static_cast<char*>(mOutputPointer.data_pointer);
458 mOutputWidth = mConfig.width;
459 mOutputHeight = mHeight;
460 mOutputPointer.height = mOutputHeight;
461 mOutputPointer.width = mOutputWidth;
462 mOutputPointer.format = Format::RGB;
463 mOutputPointer.data_pointer =
464 new char[mOutputHeight * mOutputWidth * kNumChannels];
465
466 if (!mOutputPointer.data_pointer) {
467 LOG(ERROR) << "Memory allocation failed. Exiting.";
468 return false;
469 }
470
471 Size2dInteger size = Size2dInteger(mOutputWidth, mOutputHeight);
472 mSurroundView->Update2dOutputResolution(size);
473
474 mSvTexture = new GraphicBuffer(mOutputWidth,
475 mOutputHeight,
476 HAL_PIXEL_FORMAT_RGB_888,
477 1,
478 GRALLOC_USAGE_HW_TEXTURE,
479 "SvTexture");
480 if (mSvTexture->initCheck() == OK) {
481 LOG(INFO) << "Successfully allocated Graphic Buffer";
482 } else {
483 LOG(ERROR) << "Failed to allocate Graphic Buffer";
484 return false;
485 }
486 }
487
Haoxiang Lica7719a2020-06-03 20:51:11 -0700488 if (mSurroundView->Get2dSurroundView(mInputPointers, &mOutputPointer)) {
489 LOG(INFO) << "Get2dSurroundView succeeded";
490 } else {
491 LOG(ERROR) << "Get2dSurroundView failed. "
492 << "Using memset to initialize to gray";
493 memset(mOutputPointer.data_pointer, kGrayColor,
494 mOutputHeight * mOutputWidth * kNumChannels);
495 }
496
497 void* textureDataPtr = nullptr;
498 mSvTexture->lock(GRALLOC_USAGE_SW_WRITE_OFTEN
499 | GRALLOC_USAGE_SW_READ_NEVER,
500 &textureDataPtr);
501 if (!textureDataPtr) {
502 LOG(ERROR) << "Failed to gain write access to GraphicBuffer!";
503 return false;
504 }
505
506 // Note: there is a chance that the stride of the texture is not the same
507 // as the width. For example, when the input frame is 1920 * 1080, the
508 // width is 1080, but the stride is 2048. So we'd better copy the data line
509 // by line, instead of single memcpy.
510 uint8_t* writePtr = static_cast<uint8_t*>(textureDataPtr);
511 uint8_t* readPtr = static_cast<uint8_t*>(mOutputPointer.data_pointer);
512 const int readStride = mOutputWidth * kNumChannels;
513 const int writeStride = mSvTexture->getStride() * kNumChannels;
514 if (readStride == writeStride) {
515 memcpy(writePtr, readPtr, readStride * mSvTexture->getHeight());
516 } else {
517 for (int i=0; i<mSvTexture->getHeight(); i++) {
518 memcpy(writePtr, readPtr, readStride);
519 writePtr = writePtr + writeStride;
520 readPtr = readPtr + readStride;
521 }
522 }
523 LOG(DEBUG) << "memcpy finished";
524 mSvTexture->unlock();
525
526 ANativeWindowBuffer* buffer = mSvTexture->getNativeBuffer();
527 LOG(DEBUG) << "ANativeWindowBuffer->handle: "
528 << buffer->handle;
529
Haoxiang Lica7719a2020-06-03 20:51:11 -0700530 {
531 scoped_lock<mutex> lock(mAccessLock);
532
Haoxiang Lie3011cc2020-06-10 21:33:26 -0700533 mFramesRecord.frames.svBuffers.resize(1);
534 SvBuffer& svBuffer = mFramesRecord.frames.svBuffers[0];
535 svBuffer.viewId = kSv2dViewId;
536 svBuffer.hardwareBuffer.nativeHandle = buffer->handle;
537 AHardwareBuffer_Desc* pDesc =
538 reinterpret_cast<AHardwareBuffer_Desc*>(
539 &svBuffer.hardwareBuffer.description);
540 pDesc->width = mOutputWidth;
541 pDesc->height = mOutputHeight;
542 pDesc->layers = 1;
543 pDesc->usage = GRALLOC_USAGE_HW_TEXTURE;
544 pDesc->stride = mSvTexture->getStride();
545 pDesc->format = HAL_PIXEL_FORMAT_RGB_888;
546 mFramesRecord.frames.timestampNs = elapsedRealtimeNano();
547 mFramesRecord.frames.sequenceId = sequenceId;
548
549 mFramesRecord.inUse = true;
550 mStream->receiveFrames(mFramesRecord.frames);
Haoxiang Lica7719a2020-06-03 20:51:11 -0700551 }
552
553 return true;
554}
555
Haoxiang Li35d2a702020-04-10 01:19:32 +0000556bool SurroundView2dSession::initialize() {
557 lock_guard<mutex> lock(mAccessLock, adopt_lock);
558
Haoxiang Lia9d23d12020-06-13 18:09:13 -0700559 if (!setupEvs()) {
560 LOG(ERROR) << "Failed to setup EVS components for 2d session";
561 return false;
562 }
563
Haoxiang Li35d2a702020-04-10 01:19:32 +0000564 // TODO(b/150412555): ask core-lib team to add API description for "create"
565 // method in the .h file.
566 // The create method will never return a null pointer based the API
567 // description.
568 mSurroundView = unique_ptr<SurroundView>(Create());
569
Haoxiang Liab820892020-05-20 08:50:20 -0700570 SurroundViewStaticDataParams params =
Haoxiang Lif7120b42020-06-12 12:45:36 -0700571 SurroundViewStaticDataParams(
572 mCameraParams,
573 mIOModuleConfig->sv2dConfig.sv2dParams,
574 mIOModuleConfig->sv3dConfig.sv3dParams,
575 GetUndistortionScales(),
576 mIOModuleConfig->sv2dConfig.carBoundingBox,
577 mIOModuleConfig->carModelConfig.carModel.texturesMap,
578 mIOModuleConfig->carModelConfig.carModel.partsMap);
Haoxiang Liab820892020-05-20 08:50:20 -0700579 mSurroundView->SetStaticData(params);
Haoxiang Lia9d23d12020-06-13 18:09:13 -0700580 if (mSurroundView->Start2dPipeline()) {
581 LOG(INFO) << "Start2dPipeline succeeded";
582 } else {
583 LOG(ERROR) << "Start2dPipeline failed";
584 return false;
585 }
Haoxiang Li35d2a702020-04-10 01:19:32 +0000586
Haoxiang Lia091e4a2020-06-06 20:38:46 -0700587 mInputPointers.resize(4);
588 // TODO(b/157498737): the following parameters should be fed from config
589 // files. Remove the hard-coding values once I/O module is ready.
590 for (int i=0; i<4; i++) {
591 mInputPointers[i].width = 1920;
592 mInputPointers[i].height = 1024;
593 mInputPointers[i].format = Format::RGB;
594 mInputPointers[i].cpu_data_pointer =
595 (void*) new uint8_t[mInputPointers[i].width *
596 mInputPointers[i].height *
597 kNumChannels];
Haoxiang Li35d2a702020-04-10 01:19:32 +0000598 }
Haoxiang Lia091e4a2020-06-06 20:38:46 -0700599 LOG(INFO) << "Allocated 4 input pointers";
Haoxiang Li35d2a702020-04-10 01:19:32 +0000600
Haoxiang Lif7120b42020-06-12 12:45:36 -0700601 mOutputWidth = mIOModuleConfig->sv2dConfig.sv2dParams.resolution.width;
602 mOutputHeight = mIOModuleConfig->sv2dConfig.sv2dParams.resolution.height;
Haoxiang Li35d2a702020-04-10 01:19:32 +0000603
604 mConfig.width = mOutputWidth;
605 mConfig.blending = SvQuality::HIGH;
606 mHeight = mOutputHeight;
607
608 mOutputPointer.height = mOutputHeight;
609 mOutputPointer.width = mOutputWidth;
610 mOutputPointer.format = mInputPointers[0].format;
611 mOutputPointer.data_pointer = new char[
612 mOutputHeight * mOutputWidth * kNumChannels];
613
614 if (!mOutputPointer.data_pointer) {
615 LOG(ERROR) << "Memory allocation failed. Exiting.";
616 return false;
617 }
618
619 mSvTexture = new GraphicBuffer(mOutputWidth,
620 mOutputHeight,
621 HAL_PIXEL_FORMAT_RGB_888,
622 1,
623 GRALLOC_USAGE_HW_TEXTURE,
624 "SvTexture");
625
Haoxiang Lif7120b42020-06-12 12:45:36 -0700626 mInfo.width = mIOModuleConfig->sv2dConfig.sv2dParams.physical_size.width;
627 mInfo.height = mIOModuleConfig->sv2dConfig.sv2dParams.physical_size.height;
Haoxiang Li35d2a702020-04-10 01:19:32 +0000628 mInfo.center.isValid = true;
Haoxiang Lif7120b42020-06-12 12:45:36 -0700629 mInfo.center.x = mIOModuleConfig->sv2dConfig.sv2dParams.physical_center.x;
630 mInfo.center.y = mIOModuleConfig->sv2dConfig.sv2dParams.physical_center.y;
Haoxiang Li35d2a702020-04-10 01:19:32 +0000631
632 if (mSvTexture->initCheck() == OK) {
633 LOG(INFO) << "Successfully allocated Graphic Buffer";
634 } else {
635 LOG(ERROR) << "Failed to allocate Graphic Buffer";
636 return false;
637 }
638
Haoxiang Li35d2a702020-04-10 01:19:32 +0000639 mIsInitialized = true;
640 return true;
641}
642
Haoxiang Lib88cd3e2020-06-04 10:27:31 -0700643bool SurroundView2dSession::setupEvs() {
Haoxiang Lif7120b42020-06-12 12:45:36 -0700644 // Reads the camera related information from the config object
645 const string evsGroupId = mIOModuleConfig->cameraConfig.evsGroupId;
646
Haoxiang Lib88cd3e2020-06-04 10:27:31 -0700647 // Setup for EVS
Haoxiang Lib88cd3e2020-06-04 10:27:31 -0700648 LOG(INFO) << "Requesting camera list";
Haoxiang Lif7120b42020-06-12 12:45:36 -0700649 mEvs->getCameraList_1_1(
650 [this, evsGroupId] (hidl_vec<CameraDesc> cameraList) {
Haoxiang Lib88cd3e2020-06-04 10:27:31 -0700651 LOG(INFO) << "Camera list callback received " << cameraList.size();
652 for (auto&& cam : cameraList) {
653 LOG(INFO) << "Found camera " << cam.v1.cameraId;
Haoxiang Lif7120b42020-06-12 12:45:36 -0700654 if (cam.v1.cameraId == evsGroupId) {
Haoxiang Lib88cd3e2020-06-04 10:27:31 -0700655 mCameraDesc = cam;
656 }
657 }
658 });
659
660 bool foundCfg = false;
661 std::unique_ptr<Stream> targetCfg(new Stream());
662
663 // This logic picks the configuration with the largest area that supports
664 // RGBA8888 format
665 int32_t maxArea = 0;
666 camera_metadata_entry_t streamCfgs;
667 if (!find_camera_metadata_entry(
668 reinterpret_cast<camera_metadata_t *>(mCameraDesc.metadata.data()),
669 ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS,
670 &streamCfgs)) {
671 // Stream configurations are found in metadata
672 RawStreamConfig *ptr = reinterpret_cast<RawStreamConfig *>(
673 streamCfgs.data.i32);
674 for (unsigned idx = 0; idx < streamCfgs.count; idx += kStreamCfgSz) {
675 if (ptr->direction ==
676 ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT &&
677 ptr->format == HAL_PIXEL_FORMAT_RGBA_8888) {
678
679 if (ptr->width * ptr->height > maxArea) {
680 targetCfg->id = ptr->id;
681 targetCfg->width = ptr->width;
682 targetCfg->height = ptr->height;
683
684 // This client always wants below input data format
685 targetCfg->format =
686 static_cast<GraphicsPixelFormat>(
687 HAL_PIXEL_FORMAT_RGBA_8888);
688
689 maxArea = ptr->width * ptr->height;
690
691 foundCfg = true;
692 }
693 }
694 ++ptr;
695 }
696 } else {
697 LOG(WARNING) << "No stream configuration data is found; "
698 << "default parameters will be used.";
699 }
700
701 if (!foundCfg) {
702 LOG(INFO) << "No config was found";
703 targetCfg = nullptr;
704 return false;
705 }
706
707 string camId = mCameraDesc.v1.cameraId.c_str();
708 mCamera = mEvs->openCamera_1_1(camId.c_str(), *targetCfg);
709 if (mCamera == nullptr) {
710 LOG(ERROR) << "Failed to allocate EVS Camera interface for " << camId;
711 return false;
712 } else {
713 LOG(INFO) << "Camera " << camId << " is opened successfully";
714 }
715
Haoxiang Li0c078242020-06-10 16:59:29 -0700716 map<string, AndroidCameraParams> cameraIdToAndroidParameters;
Haoxiang Lif7120b42020-06-12 12:45:36 -0700717 for (const auto& id : mIOModuleConfig->cameraConfig.evsCameraIds) {
Haoxiang Li0c078242020-06-10 16:59:29 -0700718 AndroidCameraParams params;
719 if (getAndroidCameraParams(mCamera, id, params)) {
720 cameraIdToAndroidParameters.emplace(id, params);
721 LOG(INFO) << "Camera parameters are fetched successfully for "
722 << "physical camera: " << id;
723 } else {
724 LOG(ERROR) << "Failed to get camera parameters for "
725 << "physical camera: " << id;
726 return false;
727 }
728 }
729
Haoxiang Lia9d23d12020-06-13 18:09:13 -0700730 mCameraParams =
731 convertToSurroundViewCameraParams(cameraIdToAndroidParameters);
732
733 // TODO((b/156101189): the following information should be read from the
734 // I/O module.
735 for (auto& camera : mCameraParams) {
736 camera.size.width = 1920;
737 camera.size.height = 1024;
738 camera.circular_fov = 179;
739 }
740
Haoxiang Lib88cd3e2020-06-04 10:27:31 -0700741 return true;
742}
743
744bool SurroundView2dSession::startEvs() {
745 mFramesHandler = new FramesHandler(mCamera, this);
746 Return<EvsResult> result = mCamera->startVideoStream(mFramesHandler);
747 if (result != EvsResult::OK) {
748 LOG(ERROR) << "Failed to start video stream";
749 return false;
750 } else {
751 LOG(INFO) << "Video stream was started successfully";
752 }
753
754 return true;
755}
756
Haoxiang Li35d2a702020-04-10 01:19:32 +0000757} // namespace implementation
758} // namespace V1_0
759} // namespace sv
760} // namespace automotive
761} // namespace hardware
762} // namespace android