VTS test for previewStabilization

Bug: 200197440

Test: VtsHalCameraProviderV2_4TargetTest
     --gtest_filter=PerInstance/CameraHidlTest.processCaptureRequestPreviewStab*

Change-Id: Iba71983a69d20af605924fa6f1c0697e49d911f8
Signed-off-by: Jayant Chowdhary <jchowdhary@google.com>
This commit is contained in:
Jayant Chowdhary 2021-12-03 12:20:07 -08:00
parent da43f37005
commit bf39d4db34

View file

@ -666,7 +666,7 @@ public:
void waitForBuffersReturned();
private:
private:
bool processCaptureResultLocked(const CaptureResult& results,
hidl_vec<PhysicalCameraMetadata> physicalCameraMetadata);
Return<void> notifyHelper(const hidl_vec<NotifyMsg>& msgs,
@ -906,7 +906,7 @@ public:
static Status getMandatoryConcurrentStreams(const camera_metadata_t* staticMeta,
std::vector<AvailableStream>* outputStreams);
static bool supportsPreviewStabilization(const std::string& name, sp<ICameraProvider> provider);
static Status getJpegBufferSize(camera_metadata_t *staticMeta,
uint32_t* outBufSize);
static Status isConstrainedModeAvailable(camera_metadata_t *staticMeta);
@ -953,6 +953,9 @@ public:
void processCaptureRequestInternal(uint64_t bufferusage, RequestTemplate reqTemplate,
bool useSecureOnlyCameras);
void processPreviewStabilizationCaptureRequestInternal(
bool previewStabilizationOn,
/*inout*/ std::unordered_map<std::string, nsecs_t>& cameraDeviceToTimeLag);
// Used by switchToOffline where a new result queue is created for offline reqs
void updateInflightResultQueue(std::shared_ptr<ResultMetadataQueue> resultQueue);
@ -1006,7 +1009,11 @@ protected:
// Buffers are added by process_capture_result when output buffers
// return from HAL but framework.
::android::Vector<StreamBuffer> resultOutputBuffers;
struct StreamBufferAndTimestamp {
StreamBuffer buffer;
nsecs_t timeStamp;
};
::android::Vector<StreamBufferAndTimestamp> resultOutputBuffers;
std::unordered_set<std::string> expectedPhysicalResults;
@ -1421,8 +1428,25 @@ bool CameraHidlTest::DeviceCb::processCaptureResultLocked(const CaptureResult& r
return notify;
}
request->resultOutputBuffers.appendArray(results.outputBuffers.data(),
results.outputBuffers.size());
for (const auto& buffer : results.outputBuffers) {
// wait for the fence timestamp and store it along with the buffer
// TODO: Check if we really need the dup here
sp<android::Fence> releaseFence = nullptr;
if (buffer.releaseFence && (buffer.releaseFence->numFds == 1) &&
buffer.releaseFence->data[0] >= 0) {
releaseFence = new android::Fence(dup(buffer.releaseFence->data[0]));
}
InFlightRequest::StreamBufferAndTimestamp streamBufferAndTimestamp;
streamBufferAndTimestamp.buffer = buffer;
streamBufferAndTimestamp.timeStamp = systemTime();
if (releaseFence && releaseFence->isValid()) {
releaseFence->wait(/*ms*/ 300);
nsecs_t releaseTime = releaseFence->getSignalTime();
if (streamBufferAndTimestamp.timeStamp < releaseTime)
streamBufferAndTimestamp.timeStamp = releaseTime;
}
request->resultOutputBuffers.push_back(streamBufferAndTimestamp);
}
// If shutter event is received notify the pending threads.
if (request->shutterTimestamp != 0) {
notify = true;
@ -4793,7 +4817,7 @@ void CameraHidlTest::processCaptureRequestInternal(uint64_t bufferUsage,
ASSERT_FALSE(inflightReq.errorCodeValid);
ASSERT_NE(inflightReq.resultOutputBuffers.size(), 0u);
ASSERT_EQ(testStream.id, inflightReq.resultOutputBuffers[0].streamId);
ASSERT_EQ(testStream.id, inflightReq.resultOutputBuffers[0].buffer.streamId);
// For camera device 3.8 or newer, shutterReadoutTimestamp must be
// available, and it must be >= shutterTimestamp + exposureTime, and
@ -4853,7 +4877,197 @@ void CameraHidlTest::processCaptureRequestInternal(uint64_t bufferUsage,
ASSERT_FALSE(inflightReq.errorCodeValid);
ASSERT_NE(inflightReq.resultOutputBuffers.size(), 0u);
ASSERT_EQ(testStream.id, inflightReq.resultOutputBuffers[0].streamId);
ASSERT_EQ(testStream.id, inflightReq.resultOutputBuffers[0].buffer.streamId);
}
if (useHalBufManager) {
verifyBuffersReturned(session, deviceVersion, testStream.id, cb);
}
ret = session->close();
ASSERT_TRUE(ret.isOk());
}
}
TEST_P(CameraHidlTest, processCaptureRequestPreviewStabilization) {
std::unordered_map<std::string, nsecs_t> cameraDeviceToTimeLag;
processPreviewStabilizationCaptureRequestInternal(/*previewStabilizationOn*/ false,
cameraDeviceToTimeLag);
processPreviewStabilizationCaptureRequestInternal(/*previewStabilizationOn*/ true,
cameraDeviceToTimeLag);
}
void CameraHidlTest::processPreviewStabilizationCaptureRequestInternal(
bool previewStabilizationOn,
// Used as output when preview stabilization is off, as output when its
// on.
std::unordered_map<std::string, nsecs_t>& cameraDeviceToTimeLag) {
hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(mProvider);
AvailableStream streamThreshold = {kMaxPreviewWidth, kMaxPreviewHeight,
static_cast<int32_t>(PixelFormat::IMPLEMENTATION_DEFINED)};
uint64_t bufferId = 1;
uint32_t frameNumber = 1;
::android::hardware::hidl_vec<uint8_t> settings;
for (const auto& name : cameraDeviceNames) {
int deviceVersion = getCameraDeviceVersion(name, mProviderType);
if (deviceVersion == CAMERA_DEVICE_API_VERSION_1_0) {
continue;
} else if (deviceVersion <= 0) {
ALOGE("%s: Unsupported device version %d", __func__, deviceVersion);
ADD_FAILURE();
return;
}
if (!supportsPreviewStabilization(name, mProvider)) {
ALOGI(" %s Camera device %s doesn't support preview stabilization, skipping", __func__,
name.c_str());
continue;
}
if (deviceVersion < CAMERA_DEVICE_API_VERSION_3_8) {
ALOGE("%s: device version < 3.8 must not advertise preview stabilization,"
" camera metadata validation will fail",
__func__);
ADD_FAILURE();
}
V3_2::Stream testStream;
HalStreamConfiguration halStreamConfig;
sp<ICameraDeviceSession> session;
sp<DeviceCb> cb;
bool supportsPartialResults = false;
bool useHalBufManager = false;
uint32_t partialResultCount = 0;
configureSingleStream(name, deviceVersion, mProvider, &streamThreshold,
GRALLOC1_CONSUMER_USAGE_HWCOMPOSER, RequestTemplate::PREVIEW,
&session /*out*/, &testStream /*out*/, &halStreamConfig /*out*/,
&supportsPartialResults /*out*/, &partialResultCount /*out*/,
&useHalBufManager /*out*/, &cb /*out*/);
std::shared_ptr<ResultMetadataQueue> resultQueue;
auto resultQueueRet =
session->getCaptureResultMetadataQueue([&resultQueue](const auto& descriptor) {
resultQueue = std::make_shared<ResultMetadataQueue>(descriptor);
if (!resultQueue->isValid() || resultQueue->availableToWrite() <= 0) {
ALOGE("%s: HAL returns empty result metadata fmq,"
" not use it",
__func__);
resultQueue = nullptr;
// Don't use the queue onwards.
}
});
ASSERT_TRUE(resultQueueRet.isOk());
InFlightRequest inflightReq = {1, false, supportsPartialResults, partialResultCount,
resultQueue};
Return<void> ret;
android::hardware::camera::common::V1_0::helper::CameraMetadata defaultSettings;
ret = session->constructDefaultRequestSettings(
RequestTemplate::PREVIEW, [&](auto status, const auto& req) {
ASSERT_EQ(Status::OK, status);
const camera_metadata_t* metadata =
reinterpret_cast<const camera_metadata_t*>(req.data());
defaultSettings = metadata;
settings = req;
});
ASSERT_TRUE(ret.isOk());
android::status_t metadataRet = ::android::OK;
uint8_t videoStabilizationMode = ANDROID_CONTROL_VIDEO_STABILIZATION_MODE_OFF;
if (previewStabilizationOn) {
videoStabilizationMode = ANDROID_CONTROL_VIDEO_STABILIZATION_MODE_PREVIEW_STABILIZATION;
metadataRet = defaultSettings.update(ANDROID_CONTROL_VIDEO_STABILIZATION_MODE,
&videoStabilizationMode, 1);
} else {
metadataRet = defaultSettings.update(ANDROID_CONTROL_VIDEO_STABILIZATION_MODE,
&videoStabilizationMode, 1);
}
ASSERT_EQ(metadataRet, ::android::OK);
hidl_handle buffer_handle;
StreamBuffer outputBuffer;
if (useHalBufManager) {
outputBuffer = {halStreamConfig.streams[0].id,
/*bufferId*/ 0,
buffer_handle,
BufferStatus::OK,
nullptr,
nullptr};
} else {
allocateGraphicBuffer(
testStream.width, testStream.height,
/* We don't look at halStreamConfig.streams[0].consumerUsage
* since that is 0 for output streams
*/
android_convertGralloc1To0Usage(halStreamConfig.streams[0].producerUsage,
GRALLOC1_CONSUMER_USAGE_HWCOMPOSER),
halStreamConfig.streams[0].overrideFormat, &buffer_handle);
outputBuffer = {halStreamConfig.streams[0].id,
bufferId,
buffer_handle,
BufferStatus::OK,
nullptr,
nullptr};
}
::android::hardware::hidl_vec<StreamBuffer> outputBuffers = {outputBuffer};
StreamBuffer emptyInputBuffer = {-1, 0, nullptr, BufferStatus::ERROR, nullptr, nullptr};
CaptureRequest request = {frameNumber, 0 /* fmqSettingsSize */, settings, emptyInputBuffer,
outputBuffers};
{
std::unique_lock<std::mutex> l(mLock);
mInflightMap.clear();
mInflightMap.add(frameNumber, &inflightReq);
}
Status status = Status::INTERNAL_ERROR;
uint32_t numRequestProcessed = 0;
hidl_vec<BufferCache> cachesToRemove;
Return<void> returnStatus = session->processCaptureRequest(
{request}, cachesToRemove, [&status, &numRequestProcessed](auto s, uint32_t n) {
status = s;
numRequestProcessed = n;
});
ASSERT_TRUE(returnStatus.isOk());
ASSERT_EQ(Status::OK, status);
ASSERT_EQ(numRequestProcessed, 1u);
{
std::unique_lock<std::mutex> l(mLock);
while (!inflightReq.errorCodeValid &&
((0 < inflightReq.numBuffersLeft) || (!inflightReq.haveResultMetadata))) {
auto timeout = std::chrono::system_clock::now() +
std::chrono::seconds(kStreamBufferTimeoutSec);
ASSERT_NE(std::cv_status::timeout, mResultCondition.wait_until(l, timeout));
}
ASSERT_FALSE(inflightReq.errorCodeValid);
ASSERT_NE(inflightReq.resultOutputBuffers.size(), 0u);
ASSERT_EQ(testStream.id, inflightReq.resultOutputBuffers[0].buffer.streamId);
ASSERT_TRUE(inflightReq.shutterReadoutTimestampValid);
nsecs_t readoutTimestamp = inflightReq.shutterReadoutTimestamp;
if (previewStabilizationOn) {
// Here we collect the time difference between the buffer ready
// timestamp - notify readout timestamp.
// timeLag = buffer ready timestamp - notify readout timestamp.
// timeLag(previewStabilization) must be <=
// timeLag(stabilization off) + 1 frame duration.
auto it = cameraDeviceToTimeLag.find(name.c_str());
camera_metadata_entry e;
e = inflightReq.collectedResult.find(ANDROID_SENSOR_FRAME_DURATION);
ASSERT_TRUE(e.count > 0);
nsecs_t frameDuration = e.data.i64[0];
ASSERT_TRUE(it != cameraDeviceToTimeLag.end());
nsecs_t previewStabOnLagTime =
inflightReq.resultOutputBuffers[0].timeStamp - readoutTimestamp;
ASSERT_TRUE(previewStabOnLagTime <= (it->second + frameDuration));
} else {
// Fill in the buffer ready timestamp - notify timestamp;
cameraDeviceToTimeLag[std::string(name.c_str())] =
inflightReq.resultOutputBuffers[0].timeStamp - readoutTimestamp;
}
}
if (useHalBufManager) {
@ -5434,7 +5648,7 @@ TEST_P(CameraHidlTest, processCaptureRequestBurstISO) {
ASSERT_FALSE(inflightReqs[i].errorCodeValid);
ASSERT_NE(inflightReqs[i].resultOutputBuffers.size(), 0u);
ASSERT_EQ(previewStream.id, inflightReqs[i].resultOutputBuffers[0].streamId);
ASSERT_EQ(previewStream.id, inflightReqs[i].resultOutputBuffers[0].buffer.streamId);
ASSERT_FALSE(inflightReqs[i].collectedResult.isEmpty());
ASSERT_TRUE(inflightReqs[i].collectedResult.exists(ANDROID_SENSOR_SENSITIVITY));
camera_metadata_entry_t isoResult = inflightReqs[i].collectedResult.find(
@ -5718,7 +5932,7 @@ TEST_P(CameraHidlTest, switchToOffline) {
ASSERT_FALSE(inflightReqs[i].errorCodeValid);
ASSERT_NE(inflightReqs[i].resultOutputBuffers.size(), 0u);
ASSERT_EQ(stream.id, inflightReqs[i].resultOutputBuffers[0].streamId);
ASSERT_EQ(stream.id, inflightReqs[i].resultOutputBuffers[0].buffer.streamId);
ASSERT_FALSE(inflightReqs[i].collectedResult.isEmpty());
}
@ -5914,7 +6128,7 @@ TEST_P(CameraHidlTest, flushPreviewRequest) {
if (!inflightReq.errorCodeValid) {
ASSERT_NE(inflightReq.resultOutputBuffers.size(), 0u);
ASSERT_EQ(previewStream.id, inflightReq.resultOutputBuffers[0].streamId);
ASSERT_EQ(previewStream.id, inflightReq.resultOutputBuffers[0].buffer.streamId);
} else {
switch (inflightReq.errorCode) {
case ErrorCode::ERROR_REQUEST:
@ -7536,6 +7750,47 @@ void CameraHidlTest::configurePreviewStream(const std::string &name, int32_t dev
previewStream, halStreamConfig, supportsPartialResults,
partialResultCount, useHalBufManager, outCb, streamConfigCounter);
}
bool CameraHidlTest::supportsPreviewStabilization(const std::string& name,
sp<ICameraProvider> provider) {
Return<void> ret;
sp<ICameraDevice> device3_x = nullptr;
ret = provider->getCameraDeviceInterface_V3_x(name, [&](auto status, const auto& device) {
ALOGI("getCameraDeviceInterface_V3_x returns status:%d", (int)status);
ASSERT_EQ(Status::OK, status);
ASSERT_NE(device, nullptr);
device3_x = device;
});
if (!(ret.isOk())) {
ADD_FAILURE() << "Failed to get camera device interface for " << name;
}
camera_metadata_t* staticMeta = nullptr;
ret = device3_x->getCameraCharacteristics([&](Status s, CameraMetadata metadata) {
ASSERT_EQ(Status::OK, s);
staticMeta =
clone_camera_metadata(reinterpret_cast<const camera_metadata_t*>(metadata.data()));
});
if (!(ret.isOk())) {
ADD_FAILURE() << "Failed to get camera characteristics for " << name;
}
// Go through the characteristics and see if video stabilization modes have
// preview stabilization
camera_metadata_ro_entry entry;
int retcode = find_camera_metadata_ro_entry(
staticMeta, ANDROID_CONTROL_AVAILABLE_VIDEO_STABILIZATION_MODES, &entry);
if ((0 == retcode) && (entry.count > 0)) {
for (auto i = 0; i < entry.count; i++) {
if (entry.data.u8[i] ==
ANDROID_CONTROL_VIDEO_STABILIZATION_MODE_PREVIEW_STABILIZATION) {
return true;
}
}
}
return false;
}
// Open a device session and configure a preview stream.
void CameraHidlTest::configureSingleStream(
const std::string& name, int32_t deviceVersion, sp<ICameraProvider> provider,