blob: 493679f86384273ba353580bdf5f1bb3633f8281 [file] [log] [blame]
// Copyright 2018 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "camera3_test/camera3_recording_fixture.h"
namespace camera3_test {
void Camera3RecordingFixture::SetUp() {
ASSERT_EQ(0, cam_service_.Initialize(
Camera3Service::ProcessStillCaptureResultCallback(),
base::Bind(&Camera3RecordingFixture::ProcessRecordingResult,
base::Unretained(this))))
<< "Failed to initialize camera service";
}
void Camera3RecordingFixture::ProcessRecordingResult(
int cam_id, uint32_t /*frame_number*/, ScopedCameraMetadata metadata) {
VLOGF_ENTER();
camera_metadata_ro_entry_t entry;
ASSERT_EQ(0, find_camera_metadata_ro_entry(metadata.get(),
ANDROID_SENSOR_TIMESTAMP, &entry))
<< "Failed to get sensor timestamp in recording result";
sensor_timestamp_map_[cam_id].push_back(entry.data.i64[0]);
}
// Test parameters:
// - Camera ID, width, height, frame rate
class Camera3BasicRecordingTest
: public Camera3RecordingFixture,
public ::testing::WithParamInterface<
std::tuple<int32_t, int32_t, int32_t, float, bool>> {
public:
const int32_t kRecordingDurationMs = 3000;
// Margin of frame duration in percetange. The value is adopted from
// android.hardware.camera2.cts.RecordingTest#testBasicRecording.
const float kFrameDurationMargin = 20.0;
// Tolerance of frame drop rate in percetange
const float kFrameDropRateTolerance = 5.0;
Camera3BasicRecordingTest()
: Camera3RecordingFixture(std::vector<int>(1, std::get<0>(GetParam()))),
cam_id_(std::get<0>(GetParam())),
recording_resolution_(std::get<1>(GetParam()), std::get<2>(GetParam())),
recording_frame_rate_(std::get<3>(GetParam())),
support_constant_framerate_(std::get<4>(GetParam())) {}
protected:
// |duration_ms|: total duration of recording in milliseconds
// |frame_duration_ms|: duration of each frame in milliseconds
void ValidateConstantFrameRate(float duration_ms, float frame_duration_ms);
// Finds the valid recording fps range in metadata according to
// |recording_frame_rate_| and |support_constant_framerate_| and fills the
// values in |fps_range|.
bool FindValidRecordingFpsRange(int32_t* fps_range);
int cam_id_;
ResolutionInfo recording_resolution_;
float recording_frame_rate_;
bool support_constant_framerate_;
};
void Camera3BasicRecordingTest::ValidateConstantFrameRate(
float duration_ms, float frame_duration_ms) {
ASSERT_NE(0, duration_ms);
ASSERT_NE(0, frame_duration_ms);
float max_frame_duration_ms =
frame_duration_ms * (1.0 + kFrameDurationMargin / 100.0);
float min_frame_duration_ms =
frame_duration_ms * (1.0 - kFrameDurationMargin / 100.0);
uint32_t frame_drop_count = 0;
int64_t prev_timestamp = sensor_timestamp_map_[cam_id_].front();
sensor_timestamp_map_[cam_id_].pop_front();
while (!sensor_timestamp_map_[cam_id_].empty()) {
int64_t cur_timestamp = sensor_timestamp_map_[cam_id_].front();
sensor_timestamp_map_[cam_id_].pop_front();
if (static_cast<float>(cur_timestamp - prev_timestamp) / 1000000 >
max_frame_duration_ms ||
static_cast<float>(cur_timestamp - prev_timestamp) / 1000000 <
min_frame_duration_ms) {
VLOGF(1) << "Frame drop at "
<< (prev_timestamp / 1000000 +
static_cast<int64_t>(frame_duration_ms))
<< " ms, actual " << cur_timestamp / 1000000 << " ms";
++frame_drop_count;
}
prev_timestamp = cur_timestamp;
}
float frame_drop_rate =
100.0 * frame_drop_count * frame_duration_ms / duration_ms;
ASSERT_LT(frame_drop_rate, kFrameDropRateTolerance)
<< "Camera " << cam_id_
<< " Video frame drop rate too high: " << frame_drop_rate
<< ", tolerance " << kFrameDropRateTolerance;
}
bool Camera3BasicRecordingTest::FindValidRecordingFpsRange(int32_t* fps_range) {
std::set<std::pair<int32_t, int32_t>> available_fps_ranges =
cam_service_.GetStaticInfo(cam_id_)->GetAvailableFpsRanges();
for (auto& range : available_fps_ranges) {
if (support_constant_framerate_) {
// Find [fps, fps] for device supports constant frame rate.
if (range.first == recording_frame_rate_ &&
range.second == recording_frame_rate_) {
fps_range[0] = range.first;
fps_range[1] = range.second;
return true;
}
} else {
// Find [min, max] that fulfill |min <= fps <= max| for device which does
// not support constant frame rate.
if (range.first <= recording_frame_rate_ &&
recording_frame_rate_ <= range.second) {
fps_range[0] = range.first;
fps_range[1] = range.second;
return true;
}
}
}
return false;
}
TEST_P(Camera3BasicRecordingTest, BasicRecording) {
#define ARRAY_SIZE(A) (sizeof(A) / sizeof(*(A)))
// Choose a preview resolution that is equal to or smaller than full HD so as
// to avoid the full-sized one used for the ZSL opaque stream. Ideally we
// should check it against the display resolution, but this should do for now.
// 1920x1088 is used here since on certain hardware alignment to 16 or higher
// is required.
const ResolutionInfo full_hd_alt(1920, 1088);
auto preview_resolutions =
cam_service_.GetStaticInfo(cam_id_)->GetSortedOutputResolutions(
HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED);
ResolutionInfo preview_resolution(0, 0);
for (auto it = preview_resolutions.rbegin(); it != preview_resolutions.rend();
++it) {
// Both width and height should be equal to or smaller than the bound
// according to getSupportedPreviewSizes() of cts/CameraTestUtils.java.
if (it->Width() <= full_hd_alt.Width() &&
it->Height() <= full_hd_alt.Height()) {
preview_resolution = *it;
break;
}
}
ResolutionInfo jpeg_resolution(0, 0);
cam_service_.StartPreview(cam_id_, preview_resolution, jpeg_resolution,
recording_resolution_);
ScopedCameraMetadata recording_metadata(
clone_camera_metadata(cam_service_.ConstructDefaultRequestSettings(
cam_id_, CAMERA3_TEMPLATE_VIDEO_RECORD)));
ASSERT_NE(nullptr, recording_metadata.get());
int32_t fps_range[2];
bool is_found = FindValidRecordingFpsRange(fps_range);
ASSERT_EQ(is_found, true);
EXPECT_EQ(0, UpdateMetadata(ANDROID_CONTROL_AE_TARGET_FPS_RANGE, fps_range,
ARRAY_SIZE(fps_range), &recording_metadata));
cam_service_.StartRecording(cam_id_, recording_metadata.get());
usleep(kRecordingDurationMs * 1000);
cam_service_.StopRecording(cam_id_);
if (support_constant_framerate_) {
float frame_duration_ms = 1000.0 / recording_frame_rate_;
float duration_ms =
sensor_timestamp_map_[cam_id_].size() * frame_duration_ms;
ValidateConstantFrameRate(duration_ms, frame_duration_ms);
} else {
ASSERT_EQ(cam_service_.GetStaticInfo(cam_id_)->GetHardwareLevel(),
ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL_EXTERNAL);
ASSERT_GT(sensor_timestamp_map_[cam_id_].size(), 0);
}
cam_service_.StopPreview(cam_id_);
}
INSTANTIATE_TEST_SUITE_P(Camera3RecordingFixture,
Camera3BasicRecordingTest,
::testing::ValuesIn(ParseRecordingParams()));
} // namespace camera3_test