You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

230 lines
9.3 KiB

// License: Apache 2.0. See LICENSE file in root directory.
// Copyright(c) 2021 Intel Corporation. All Rights Reserved.
//#cmake: static!
//#test:device D435
#include <unit-tests/test.h>
#include "../live-common.h"
using namespace rs2;
constexpr int RECEIVE_FRAMES_TIME = 10;
constexpr float LOW_FPS = 30;
constexpr float HIGH_FPS = 60;
TEST_CASE( "Syncer dynamic FPS - throughput test" )
{
typedef enum configuration
{
IR_ONLY,
IR_RGB_EXPOSURE,
STOP
}configuration;
class ir_cfg
{
public:
ir_cfg(sensor rgb_sensor,
sensor ir_sensor,
std::vector<rs2::stream_profile > rgb_stream_profile,
std::vector<rs2::stream_profile > ir_stream_profile) : _rgb_sensor(rgb_sensor), _ir_sensor(ir_sensor),
_rgb_stream_profile(rgb_stream_profile), _ir_stream_profile(ir_stream_profile) {}
void test_configuration(configuration test)
{
std::cout << "==============================================" << std::endl;
std::string cfg = test == IR_ONLY ? "IR Only" : "IR + RGB";
std::cout << "Configuration: " << cfg << std::endl << std::endl;
start_streaming(test);
process_validate_frames(test);
stop_streaming(test);
// analysis
analysis(test, _rgb_frames_arrival_info, "Color");
analysis(test, _ir_frames_arrival_info);
}
private:
void set_ir_exposure(float value = 18000.0f)
{
if (_ir_sensor.supports(RS2_OPTION_EXPOSURE))
REQUIRE_NOTHROW(_ir_sensor.set_option(RS2_OPTION_EXPOSURE, value));
}
void start_streaming(configuration test)
{
_ir_sensor.set_option(RS2_OPTION_EXPOSURE, 1);
_ir_sensor.open(_ir_stream_profile); // ir streams in all configurations
_ir_sensor.start(_sync);
if (test == IR_RGB_EXPOSURE)
{
_rgb_sensor.open(_rgb_stream_profile);
_rgb_sensor.start(_sync);
}
}
void stop_streaming(configuration test)
{
_ir_sensor.stop();
_ir_sensor.close();
if (test == IR_RGB_EXPOSURE)
{
_rgb_sensor.stop();
_rgb_sensor.close();
}
set_ir_exposure(1.0f);
}
void process_validate_frames(configuration test)
{
auto t_start = std::chrono::system_clock::now();
auto t_end = std::chrono::system_clock::now();
bool exposure_set = false;
auto process_frame = [&](const rs2::frame& f)
{
std::lock_guard<std::mutex> lock(_mutex);
auto stream_type = std::string(f.get_profile().stream_name());
// Only IR fps is relevant for this test, IR1 and IR2 have same fps so it is enough to get only one of them
if (!(stream_type == "Infrared 1" || stream_type == "Color"))
return;
if (!f.supports_frame_metadata(RS2_FRAME_METADATA_ACTUAL_FPS) || !f.supports_frame_metadata(RS2_FRAME_METADATA_FRAME_TIMESTAMP))
return;
auto frame_num = f.get_frame_number();
auto actual_fps = f.get_frame_metadata(RS2_FRAME_METADATA_ACTUAL_FPS) / 1000.f;
auto frame_arrival = f.get_frame_metadata(RS2_FRAME_METADATA_FRAME_TIMESTAMP); // usec
if (stream_type == "Infrared 1")
_ir_frames_arrival_info.push_back({ (float)frame_arrival, actual_fps });
if (stream_type == "Color")
_rgb_frames_arrival_info.push_back({ (float)frame_arrival, actual_fps });
};
float delta = (float)std::chrono::duration_cast<std::chrono::seconds>(t_end - t_start).count();
while (delta < RECEIVE_FRAMES_TIME)
{
if (!exposure_set && delta > RECEIVE_FRAMES_TIME / 2)
{
set_ir_exposure(); // set exposure to 18000 after 5 sec to get fps = 30, set to 60000 to get fps = 15
exposure_set = true;
}
auto fs = _sync.wait_for_frames();
for (const rs2::frame& ff : fs)
{
process_frame(ff);
}
t_end = std::chrono::system_clock::now();
delta = (float)std::chrono::duration_cast<std::chrono::seconds>(t_end - t_start).count();
}
}
void analysis(configuration test, std::vector <std::pair<float, float>>& frames_arrival_info, std::string stream_type = "Infrared 1")
{
if (frames_arrival_info.empty())
return;
std::vector<std::pair<float, float>> vec[2]; // separate frames according to fps (before and after setting exposure)
std::vector<std::pair<float, float>> extra_frames; // frames with unstable fps are received after changing exposure
for (auto& frm : frames_arrival_info)
{
// used ratio instead of precised fps because syncer doesn't change fps to exact value when running RGB
if (frm.second / HIGH_FPS > 0.9)
vec[0].push_back(frm);
else if (frm.second / LOW_FPS > 0.9)
vec[1].push_back(frm);
else
extra_frames.push_back(frm);
}
int i = 0;
for (auto& v : vec)
{
if (v.size() < 10)
continue;
auto dt = (v.back().first - v.front().first)/ 1000000;
auto actual_fps = v.front().second;
float calc_fps = (float)v.size() / dt;
float fps_ratio = fabs(1 - calc_fps / actual_fps);
CAPTURE(stream_type, actual_fps, calc_fps, v.size());
CHECK(fps_ratio < 0.1);
check_frame_drops(v);
i += 1;
}
CHECK(extra_frames.size() / frames_arrival_info.size() < 0.1);
}
void check_frame_drops(std::vector<std::pair<float, float>> frames)
{
float prev_frame_time = 0.0f;
bool first = true;
int count_drops = 0;
for (auto& frame : frames)
{
auto actual_fps = frame.second;
float expected_dt_ms = 1000 / actual_fps; // convert sec -> msec
auto frame_time = frame.first;
float calc_dt_msec = ((float)frame_time - prev_frame_time)/1000; //convert usec -> msec
float dt_msec_ratio = calc_dt_msec / expected_dt_ms;
CAPTURE(expected_dt_ms, calc_dt_msec, dt_msec_ratio, frame_time, prev_frame_time);
if (!first && dt_msec_ratio > 1.5)
count_drops++;
prev_frame_time = frame_time;
first = false;
}
float count_drops_ratio = (float)count_drops / frames.size();
CHECK(count_drops_ratio < 0.1);
}
sensor _rgb_sensor;
sensor _ir_sensor;
std::vector<rs2::stream_profile > _rgb_stream_profile;
std::vector<rs2::stream_profile > _ir_stream_profile;
std::vector <std::pair<float, float>> _ir_frames_arrival_info; //{HW timestamp, fps}
std::vector <std::pair<float, float>> _rgb_frames_arrival_info; //{HW timestamp, fps}
std::mutex _mutex;
rs2::syncer _sync;
};
// Require at least one device to be plugged in
auto dev = find_first_device_or_exit();
auto sensors = dev.query_sensors();
int width = 848;
int height = 480;
// extract IR/RGB sensors
sensor rgb_sensor;
sensor ir_sensor;
std::vector<rs2::stream_profile > rgb_stream_profile;
std::vector<rs2::stream_profile > ir_stream_profile;
for (auto& s : sensors)
{
auto info = std::string(s.get_info(RS2_CAMERA_INFO_NAME));
if( info == "RGB Camera" )
rgb_sensor = s;
if( info == "Stereo Module" )
ir_sensor = s;
auto stream_profiles = s.get_stream_profiles();
for (auto& sp : stream_profiles)
{
auto vid = sp.as<rs2::video_stream_profile>();
if (!(vid.width() == width && vid.height() == height && vid.fps() == 60)) continue;
if (sp.stream_type() == RS2_STREAM_COLOR && sp.format() == RS2_FORMAT_RGB8)
rgb_stream_profile.push_back(sp);
if (sp.stream_type() == RS2_STREAM_INFRARED && sp.format() == RS2_FORMAT_Y8)
ir_stream_profile.push_back(sp);
}
if (s.supports(RS2_OPTION_GLOBAL_TIME_ENABLED))
s.set_option(RS2_OPTION_GLOBAL_TIME_ENABLED, 0);
}
REQUIRE( rgb_sensor );
REQUIRE( ir_sensor );
if (ir_sensor.supports(RS2_OPTION_ENABLE_AUTO_EXPOSURE))
ir_sensor.set_option(RS2_OPTION_ENABLE_AUTO_EXPOSURE, false);
if (rgb_sensor.supports(RS2_OPTION_ENABLE_AUTO_EXPOSURE))
rgb_sensor.set_option(RS2_OPTION_ENABLE_AUTO_EXPOSURE, false);
// test configurations
configuration tests[2] = { IR_ONLY, IR_RGB_EXPOSURE }; // {cfg, exposure}
for (auto& test : tests)
{
CAPTURE(test);
ir_cfg test_cfg(rgb_sensor, ir_sensor, rgb_stream_profile, ir_stream_profile);
test_cfg.test_configuration(test);
}
}