From 3e69744f0f24c6c455fddbdcb160bdb1ee773050 Mon Sep 17 00:00:00 2001 From: Changyeon Jo Date: Fri, 27 Mar 2020 14:19:46 -0700 Subject: [PATCH 1/2] User allocated EVS camera capture buffers This change introduces a new API to import frame capture buffers allocated by the clients. Bug: 152493110 Test: m -j and run /system/bin/evs_app --test --extmem Change-Id: I679c61719e4d0e3a7d0c41110afe66e0a4ccb305 --- automotive/evs/1.1/IEvsCamera.hal | 18 ++++++++++++++++++ automotive/evs/1.1/default/EvsCamera.cpp | 8 ++++++++ automotive/evs/1.1/default/EvsCamera.h | 2 ++ automotive/evs/1.1/types.hal | 3 +++ current.txt | 4 ++-- 5 files changed, 33 insertions(+), 2 deletions(-) diff --git a/automotive/evs/1.1/IEvsCamera.hal b/automotive/evs/1.1/IEvsCamera.hal index 38e6c4242c..3e7ac2b299 100644 --- a/automotive/evs/1.1/IEvsCamera.hal +++ b/automotive/evs/1.1/IEvsCamera.hal @@ -215,4 +215,22 @@ interface IEvsCamera extends @1.0::IEvsCamera { */ setExtendedInfo_1_1(uint32_t opaqueIdentifier, vec opaqueValue) generates (EvsResult result); + + /** + * Import external buffers to capture frames + * + * This API must be called with a physical camera device identifier. + * + * @param buffers A list of buffers allocated by the caller. EvsCamera + * will use these buffers to capture frames, in addition to + * other buffers already in its buffer pool. + * @return result EvsResult::OK if it succeeds to import buffers. + * EvsResult::UNDERLYING_SERVICE_ERROR if this is called + * for logical camera devices or EVS fails to import + * buffers. + * delta The amount of buffer pool size changes after importing + * given buffers. + */ + importExternalBuffers(vec buffers) + generates (EvsResult result, int32_t delta); }; diff --git a/automotive/evs/1.1/default/EvsCamera.cpp b/automotive/evs/1.1/default/EvsCamera.cpp index 5196c9532b..0e69ed408b 100644 --- a/automotive/evs/1.1/default/EvsCamera.cpp +++ b/automotive/evs/1.1/default/EvsCamera.cpp @@ -354,6 +354,14 @@ Return EvsCamera::getExtendedInfo_1_1(uint32_t opaqueIdentifier, } +Return +EvsCamera::importExternalBuffers(const hidl_vec& /* buffers */, + importExternalBuffers_cb _hidl_cb) { + ALOGW("%s is not implemented yet.", __FUNCTION__); + _hidl_cb(EvsResult::UNDERLYING_SERVICE_ERROR, 0); + return {}; +} + bool EvsCamera::setAvailableFrames_Locked(unsigned bufferCount) { if (bufferCount < 1) { diff --git a/automotive/evs/1.1/default/EvsCamera.h b/automotive/evs/1.1/default/EvsCamera.h index 0fa83b428d..6163a34e08 100644 --- a/automotive/evs/1.1/default/EvsCamera.h +++ b/automotive/evs/1.1/default/EvsCamera.h @@ -82,6 +82,8 @@ public: const hidl_vec& opaqueValue) override; Return getExtendedInfo_1_1(uint32_t opaqueIdentifier, getExtendedInfo_1_1_cb _hidl_cb) override; + Return importExternalBuffers(const hidl_vec& buffers, + importExternalBuffers_cb _hidl_cb) override; static sp Create(const char *deviceName); static sp Create(const char *deviceName, diff --git a/automotive/evs/1.1/types.hal b/automotive/evs/1.1/types.hal index b34e7e7d65..1f69f09b5b 100644 --- a/automotive/evs/1.1/types.hal +++ b/automotive/evs/1.1/types.hal @@ -70,6 +70,9 @@ struct BufferDesc { */ int64_t timestamp; + /** + * Frame metadata. This is opaque to EVS manager. + */ vec metadata; }; diff --git a/current.txt b/current.txt index 183d00637b..3a6946535d 100644 --- a/current.txt +++ b/current.txt @@ -642,13 +642,13 @@ d06fc14b325beeef06bd39de8f178f490d9e9095255626866071aab42be1fc40 android.hardwar 07e387bd8bc0e4df5f372515ed960a0b1ae74ea7231d4490a0bb09b07046e4f1 android.hardware.automotive.can@1.0::ICanMessageListener 2166132d6c247630a193217b4338074f634d6691b1ed6796cb26b3812e90b46e android.hardware.automotive.can@1.0::ICloseHandle 83355471a3b6d7f777d3f129714585ffb77d9b6f8a3d0365741969631efb81b2 android.hardware.automotive.can@1.0::types -8afd93d525cf17818e3d46e72f30debeaacc6fb166a59a8e25272f2baeb0ef7a android.hardware.automotive.evs@1.1::IEvsCamera +50bfbeef15d7451bd07e4ad460fbcb7ff80521b89bb8049035c0d458b4125ae4 android.hardware.automotive.evs@1.1::IEvsCamera 89ff5ab18b3069f21a57f559b290caa50670f0ae1b74178f630183aef39b496b android.hardware.automotive.evs@1.1::IEvsCameraStream 4c67f768067a0aceac74381f6f62e778ab3b6a18f47db3c9b98c58190ef5619d android.hardware.automotive.evs@1.1::IEvsDisplay 87958d728d7c0ee9b9391ab4a072b097914921a7b38f7dc3df427f933a5b528e android.hardware.automotive.evs@1.1::IEvsEnumerator f53b4e8de6209c6d0fa9036005671b34a2f98328b51423d3a5137a43bf42c84d android.hardware.automotive.evs@1.1::IEvsUltrasonicsArray 0460bacbde906a846a3d71b2b7b33d6927cac3ff072e523ffac7853577464406 android.hardware.automotive.evs@1.1::IEvsUltrasonicsArrayStream -8a156203892de3cfa47baaccabef3c45b3315cae93b332357598d60896b1ac7f android.hardware.automotive.evs@1.1::types +3e374b5c4777f959f62a320abb3b9edca8874e24e383dbb19c66d224f151b363 android.hardware.automotive.evs@1.1::types 4e4904c4067dadae974ddf90351f362331dcd04bba1d890d313cc8ba91f68c15 android.hardware.automotive.sv@1.0::ISurroundView2dSession 63336e9d03f545020ff2982ff76d9d8c44fa76ad476293b5ef6732cbbd71e61b android.hardware.automotive.sv@1.0::ISurroundView3dSession b7015428cd52ce8192d13bfcbf2c4455cda3727d57f2aac80d65a1747104f5ac android.hardware.automotive.sv@1.0::ISurroundViewService From 8b06871849c52f70b5f1b06243548a517283ae91 Mon Sep 17 00:00:00 2001 From: Changyeon Jo Date: Wed, 1 Apr 2020 10:51:28 -0700 Subject: [PATCH 2/2] Add CameraStreamExternalBuffering test case This change adds a VTS test case to validate a new IEvsCamera::importExtenralBuffers() API. New test case allocates graphic buffers and passes them via a new API call. Bug: 152493110 Test: vts-tradefed VtsHalEvsV1_1_TargetTest Change-Id: I157f3cf45092a9a4ca8bf5bf9ea54aa62d15225c --- .../functional/VtsHalEvsV1_1TargetTest.cpp | 137 ++++++++++++++++++ 1 file changed, 137 insertions(+) diff --git a/automotive/evs/1.1/vts/functional/VtsHalEvsV1_1TargetTest.cpp b/automotive/evs/1.1/vts/functional/VtsHalEvsV1_1TargetTest.cpp index 368a6d4d2d..6a386c3080 100644 --- a/automotive/evs/1.1/vts/functional/VtsHalEvsV1_1TargetTest.cpp +++ b/automotive/evs/1.1/vts/functional/VtsHalEvsV1_1TargetTest.cpp @@ -50,6 +50,8 @@ static const float kNanoToSeconds = 0.000000001f; #include #include #include +#include +#include #include #include @@ -66,6 +68,7 @@ using ::android::hardware::hidl_string; using ::android::sp; using ::android::wp; using ::android::hardware::camera::device::V3_2::Stream; +using ::android::hardware::automotive::evs::V1_1::BufferDesc; using ::android::hardware::automotive::evs::V1_0::DisplayDesc; using ::android::hardware::automotive::evs::V1_0::DisplayState; using ::android::hardware::graphics::common::V1_0::PixelFormat; @@ -2230,6 +2233,140 @@ TEST_P(EvsHidlTest, LogicalCameraMetadata) { } +/* + * CameraStreamExternalBuffering: + * This is same with CameraStreamBuffering except frame buffers are allocated by + * the test client and then imported by EVS framework. + */ +TEST_P(EvsHidlTest, CameraStreamExternalBuffering) { + LOG(INFO) << "Starting CameraStreamExternalBuffering test"; + + // Arbitrary constant (should be > 1 and less than crazy) + static const unsigned int kBuffersToHold = 6; + + // Get the camera list + loadCameraList(); + + // Using null stream configuration makes EVS uses the default resolution and + // output format. + Stream nullCfg = {}; + + // Acquire the graphics buffer allocator + android::GraphicBufferAllocator& alloc(android::GraphicBufferAllocator::get()); + const auto usage = GRALLOC_USAGE_HW_TEXTURE | + GRALLOC_USAGE_SW_READ_RARELY | + GRALLOC_USAGE_SW_WRITE_OFTEN; + const auto format = HAL_PIXEL_FORMAT_RGBA_8888; + const auto width = 640; + const auto height = 360; + + // Allocate buffers to use + hidl_vec buffers; + for (auto i = 0; i < kBuffersToHold; ++i) { + unsigned pixelsPerLine; + buffer_handle_t memHandle = nullptr; + android::status_t result = alloc.allocate(width, + height, + format, + 1, + usage, + &memHandle, + &pixelsPerLine, + 0, + "EvsApp"); + if (result != android::NO_ERROR) { + LOG(ERROR) << __FUNCTION__ << " failed to allocate memory."; + } else { + BufferDesc buf; + AHardwareBuffer_Desc* pDesc = + reinterpret_cast(&buf.buffer.description); + pDesc->width = width; + pDesc->height = height; + pDesc->layers = 1; + pDesc->format = format; + pDesc->usage = usage; + pDesc->stride = pixelsPerLine; + buf.buffer.nativeHandle = memHandle; + buf.bufferId = i; // Unique number to identify this buffer + buffers[i] = buf; + } + } + + // Test each reported camera + for (auto&& cam: cameraInfo) { + bool isLogicalCam = false; + getPhysicalCameraIds(cam.v1.cameraId, isLogicalCam); + + sp pCam = + IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg)) + .withDefault(nullptr); + ASSERT_NE(pCam, nullptr); + + // Store a camera handle for a clean-up + activeCameras.push_back(pCam); + + // Request to import buffers + EvsResult result = EvsResult::OK; + int delta = 0; + pCam->importExternalBuffers(buffers, + [&] (auto _result, auto _delta) { + result = _result; + delta = _delta; + }); + if (isLogicalCam) { + EXPECT_EQ(result, EvsResult::UNDERLYING_SERVICE_ERROR); + continue; + } + + EXPECT_EQ(result, EvsResult::OK); + EXPECT_GE(delta, 0); + + // Set up a frame receiver object which will fire up its own thread. + sp frameHandler = new FrameHandler(pCam, cam, + nullptr, + FrameHandler::eNoAutoReturn); + + // Start the camera's video stream + bool startResult = frameHandler->startStream(); + ASSERT_TRUE(startResult); + + // Check that the video stream stalls once we've gotten exactly the number of buffers + // we requested since we told the frameHandler not to return them. + sleep(1); // 1 second should be enough for at least 5 frames to be delivered worst case + unsigned framesReceived = 0; + frameHandler->getFramesCounters(&framesReceived, nullptr); + ASSERT_EQ(kBuffersToHold, framesReceived) << "Stream didn't stall at expected buffer limit"; + + + // Give back one buffer + bool didReturnBuffer = frameHandler->returnHeldBuffer(); + EXPECT_TRUE(didReturnBuffer); + + // Once we return a buffer, it shouldn't take more than 1/10 second to get a new one + // filled since we require 10fps minimum -- but give a 10% allowance just in case. + usleep(110 * kMillisecondsToMicroseconds); + frameHandler->getFramesCounters(&framesReceived, nullptr); + EXPECT_EQ(kBuffersToHold+1, framesReceived) << "Stream should've resumed"; + + // Even when the camera pointer goes out of scope, the FrameHandler object will + // keep the stream alive unless we tell it to shutdown. + // Also note that the FrameHandle and the Camera have a mutual circular reference, so + // we have to break that cycle in order for either of them to get cleaned up. + frameHandler->shutdown(); + + // Explicitly release the camera + pEnumerator->closeCamera(pCam); + activeCameras.clear(); + } + + // Release buffers + for (auto& b : buffers) { + alloc.free(b.buffer.nativeHandle); + } + buffers.resize(0); +} + + /* * UltrasonicsArrayOpenClean: * Opens each ultrasonics arrays reported by the enumerator and then explicitly closes it via a