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:
parent
da43f37005
commit
bf39d4db34
1 changed files with 265 additions and 10 deletions
|
@ -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,
|
||||
|
|
Loading…
Reference in a new issue