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
diff --git a/automotive/evs/1.1/vts/functional/VtsHalEvsV1_1TargetTest.cpp b/automotive/evs/1.1/vts/functional/VtsHalEvsV1_1TargetTest.cpp
index 368a6d4..6a386c3 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 @@
#include <system/camera_metadata.h>
#include <ui/DisplayConfig.h>
#include <ui/DisplayState.h>
+#include <ui/GraphicBuffer.h>
+#include <ui/GraphicBufferAllocator.h>
#include <gtest/gtest.h>
#include <hidl/GtestPrinter.h>
@@ -66,6 +68,7 @@
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;
@@ -2231,6 +2234,140 @@
/*
+ * 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<BufferDesc> 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<AHardwareBuffer_Desc *>(&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<IEvsCamera_1_1> 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> 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
* call to closeUltrasonicsArray. Then repeats the test to ensure all ultrasonics arrays