File plugin.cpp
File List > ada > device_tx > plugin.cpp
Go to the documentation of this file
#include "plugin.hpp"
#include
#include
using namespace ILLIXR;
using namespace ILLIXR::data_format;
[[maybe_unused]] device_tx::device_tx(const std::string& name_, phonebook* pb_)
: threadloop{name_, pb_}
, switchboard_{phonebook_->lookup_impl<switchboard>()}
, clock_{phonebook_->lookup_impl<relative_clock>()} // make sure you have the right IP address
, stoplight_{phonebook_->lookup_impl<stoplight>()}
, ada_writer_{switchboard_->get_network_writer<switchboard::event_wrapper<std::string>>(
"ada_data",
network::topic_config{network::topic_config::SerializationMethod::PROTOBUF,
network::topic_config::TransportMethod::TCP, std::chrono::milliseconds(0)})} {
if (!std::filesystem::exists(data_path_)) {
if (!std::filesystem::create_directory(data_path_)) {
spdlog::get("illixr")->error("Failed to create data directory.");
}
}
starting_timestamp_.open(data_path_ + "/starting_timestamp_.csv");
sending_timestamp_.open(data_path_ + "/sending_timestamp_.csv");
frame_send_timing_.open(data_path_ + "/frame_send_latency.csv");
if (!starting_timestamp_ || !sending_timestamp_ || !frame_send_timing_) {
spdlog::get("illixr")->error("[device_tx] Failed to open one or more log files.");
}
const char* env_value = std::getenv("FRAME_COUNT");
const char* env_value_1 = std::getenv("FPS");
if (env_value != nullptr && env_value_1 != nullptr) {
try {
frame_count_ = std::stoul(env_value);
fps_ = std::stoul(env_value_1);
} catch (...) {
spdlog::get("illixr")->error("device_tx: invalid FRAME_COUNT/FPS; falling back to {} / {}", frame_count_, fps_);
}
} else {
spdlog::get("illixr")->error("device_tx: FRAME_COUNT or FPS not set; using defaults {} / {}", frame_count_, fps_);
}
spdlog::get("illixr")->info("device_tx: FRAME_COUNT {} /FPS {}", frame_count_, fps_);
}
void device_tx::start() {
threadloop::start();
encoder_ = std::make_unique<ada_video_encoder>(
// First callback for img0 and img1
[this](const GstMapInfo& img0, const GstMapInfo& img1) {
std::lock_guard<std::mutex> lock{mutex_};
msb_bytes_.assign(reinterpret_cast<const char*>(img0.data), img0.size);
lsb_bytes_.assign(reinterpret_cast<const char*>(img1.data), img1.size);
img_ready_ = true;
cond_var_.notify_one();
});
encoder_->init();
switchboard_->schedule<scene_recon_type>(id_, "ScanNet_Data",
[this](switchboard::ptr<const scene_recon_type> datum, std::size_t) {
this->send_scene_recon_data(datum);
});
}
void device_tx::_p_one_iteration() {
while (!stoplight_->check_should_stop()) {
std::this_thread::sleep_for(std::chrono::milliseconds(1));
}
}
void device_tx::send_scene_recon_data(switchboard::ptr<const scene_recon_type> datum) {
auto t0 = std::chrono::high_resolution_clock::now();
auto since_epoch = t0.time_since_epoch();
auto millis = std::chrono::duration_cast<std::chrono::milliseconds>(since_epoch).count();
starting_timestamp_ << frame_id_ << " " << millis << "\n";
if (frame_id_ == 0) {
spdlog::get("illixr")->info("[device_tx] Start sending encoded packets");
}
// Build Payload
pose = outgoing_payload->mutable_input_pose();
// pyh assign outgoing pose & image information
pose->set_p_x(datum->pose.position.x());
pose->set_p_y(datum->pose.position.y());
pose->set_p_z(datum->pose.position.z());
pose->set_o_x(datum->pose.orientation.x());
pose->set_o_y(datum->pose.orientation.y());
pose->set_o_z(datum->pose.orientation.z());
pose->set_o_w(datum->pose.orientation.w());
// Depth
cv::Mat cur_depth = datum->depth;
sr_input_proto::ImgData* depth_img_msb = outgoing_payload->mutable_depth_img_msb_data();
sr_input_proto::ImgData* depth_img_lsb = outgoing_payload->mutable_depth_img_lsb_data();
depth_img_msb->set_rows(cur_depth.rows);
depth_img_msb->set_columns(cur_depth.cols);
depth_img_lsb->set_rows(cur_depth.rows);
depth_img_lsb->set_columns(cur_depth.cols);
cv::Mat depth_msb, depth_lsb;
auto decompose_start = std::chrono::high_resolution_clock::now();
decompose_16bit_to_8bit(cur_depth, depth_msb, depth_lsb);
auto decompose_end = std::chrono::high_resolution_clock::now();
auto duration_decompose = std::chrono::duration_cast<std::chrono::microseconds>(decompose_end - decompose_start).count();
frame_send_timing_ << "Decompose " << (static_cast<double>(duration_decompose) / 1000.0) << "\n";
auto depth_encoding_start = std::chrono::high_resolution_clock::now();
{
std::lock_guard<std::mutex> lk{mutex_};
img_ready_ = false;
}
encoder_->enqueue(depth_msb, depth_lsb);
{
std::unique_lock<std::mutex> lock{mutex_};
cond_var_.wait(lock, [this]() {
return img_ready_;
});
depth_img_msb->mutable_img_data()->swap(msb_bytes_);
depth_img_lsb->mutable_img_data()->swap(lsb_bytes_);
depth_img_msb->set_size(static_cast<int64_t>(depth_img_msb->img_data().size()));
depth_img_lsb->set_size(static_cast<int64_t>(depth_img_lsb->img_data().size()));
}
auto depth_encoding_end = std::chrono::high_resolution_clock::now();
auto duration_depth_encoding =
std::chrono::duration_cast<std::chrono::microseconds>(depth_encoding_end - depth_encoding_start).count();
frame_send_timing_ << "Encode " << (static_cast<double>(duration_depth_encoding) / 1000.0) << " " << depth_img_msb->size()
<< " " << depth_img_lsb->size() << "\n";
outgoing_payload->set_id(static_cast<int>(frame_id_));
// serialize protobuf directly into place (no temporary std::string)
send_buf_ = outgoing_payload->SerializeAsString();
// send
ada_writer_.put(std::make_shared<switchboard::event_wrapper<std::string>>(send_buf_ + delimiter));
spdlog::get("illixr")->debug(
"Pose of frame {}: {}, {}, {}; {}, {}, {}, {}", frame_id_, outgoing_payload->input_pose().p_x(),
outgoing_payload->input_pose().p_y(), outgoing_payload->input_pose().p_z(), outgoing_payload->input_pose().o_w(),
outgoing_payload->input_pose().o_x(), outgoing_payload->input_pose().o_y(), outgoing_payload->input_pose().o_z());
{
std::lock_guard<std::mutex> lk{mutex_};
depth_img_msb->mutable_img_data()->swap(msb_bytes_);
depth_img_lsb->mutable_img_data()->swap(lsb_bytes_);
}
auto fullframe = std::chrono::high_resolution_clock::now();
auto fullframe_duration = std::chrono::duration_cast<std::chrono::microseconds>(fullframe - t0).count();
frame_send_timing_ << "FullFrame " << (static_cast<double>(fullframe_duration) / 1000.0) << " " << send_buf_.size() << "\n";
if (frame_id_ % fps_ == 0 && frame_id_ > 0) {
since_epoch = fullframe.time_since_epoch();
millis = std::chrono::duration_cast<std::chrono::milliseconds>(since_epoch).count();
sending_timestamp_ << frame_id_ << " " << millis << "\n";
}
if (frame_id_ == frame_count_ - 1) {
printf("finish sending\n");
frame_send_timing_.flush();
sending_timestamp_.flush();
starting_timestamp_.flush();
}
frame_id_++;
delete outgoing_payload;
outgoing_payload = new sr_input_proto::SRSendData();
}
void device_tx::decompose_16bit_to_8bit(const cv::Mat& depth16, cv::Mat& out_msb, cv::Mat& out_lsb) {
CV_Assert(depth16.type() == CV_16U);
out_msb.create(depth16.size(), CV_8UC1);
out_lsb.create(depth16.size(), CV_8UC1);
const int rows = depth16.rows;
const int cols = depth16.cols;
for (int y = 0; y < rows; ++y) {
const auto src = depth16.ptr<uint16_t>(y);
auto msb = out_msb.ptr<uint8_t>(y);
auto lsb = out_lsb.ptr<uint8_t>(y);
for (int x = 0; x < cols; ++x) {
const uint16_t v = src[x];
msb[x] = static_cast<uint8_t>(v >> 8);
lsb[x] = static_cast<uint8_t>(v & 0xFF);
}
}
}
device_tx::~device_tx() {
delete outgoing_payload;
}
PLUGIN_MAIN(device_tx)