Skip to content

Commit

Permalink
map and chart widgets (#25)
Browse files Browse the repository at this point in the history
  • Loading branch information
neri14 authored Aug 28, 2024
1 parent 00d66e0 commit 1b1e7eb
Show file tree
Hide file tree
Showing 18 changed files with 495 additions and 46 deletions.
39 changes: 16 additions & 23 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,27 +3,6 @@
[![Build and Test](https://github.com/neri14/videographer/actions/workflows/build-and-test.yml/badge.svg)](https://github.com/neri14/videographer/actions/workflows/build-and-test.yml)


## ToDo
- cleanup pipeline implementation after adding gpu
- add -g --gpu flag to control if generation goes to cpu or gpu
- add argument for controlling upscale (if then also control applied template)
- implement overlay caching onto a single buffer of static texts and if overlay doesnt change between frames


## Dependencies

Packages required in system to build the application

- CMake >= 3.23
- Make / Ninja
- GCC >= 14.x
- googlemock
- gstreamer >= 1.24
- cairo
- pango
- pugixml


## Building and testing

1. ```cmake -B build``` generate cmake files to build directory
Expand All @@ -36,12 +15,26 @@ Packages required in system to build the application

1. Get video and telemetry
1. Run concat tool to combine the clips
1. Run trim tool to get final base video
1. Run trim tool to create final raw video
1. Run alignment tool and figure out offset
1. Run generator app to generate base video (upscaled to 4K for YT)
1. Run generator app to generate final video (for YT - set upscale to 4K (```-r 3840x2160```))
1. Upload


## Dependencies

Packages required in system to build the application

- CMake >= 3.23
- Make / Ninja
- GCC >= 14.x
- googlemock
- gstreamer >= 1.24
- cairo
- pango
- pugixml


## Alignment Tool

Python alignment tool is located in tools/alignment.
Expand Down
16 changes: 11 additions & 5 deletions src/telemetry/telemetry.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ namespace helper {
}
}

telemetry::telemetry(std::shared_ptr<datapoint_sequence> seq, long offset)
telemetry::telemetry(std::shared_ptr<datapoint_sequence> seq, long offset) :
points(*seq)
{
if (!seq) {
log.warning("No telemetry loaded");
Expand All @@ -26,7 +27,7 @@ telemetry::telemetry(std::shared_ptr<datapoint_sequence> seq, long offset)
bool first = true;
for (auto& data : *seq) {
long us = std::chrono::duration_cast<std::chrono::microseconds>(data->timestamp - first_timestamp).count();
points[us+offset] = data;
time_points[us+offset] = data;

if (!first) {
sum += std::chrono::duration_cast<std::chrono::microseconds>(data->timestamp - prev_timestamp).count();
Expand All @@ -43,14 +44,19 @@ std::shared_ptr<datapoint> telemetry::get(double timestamp) const
{
long us = helper::in_microseconds(timestamp);

if (points.begin()->first > us) {
if (time_points.begin()->first > us) {
return nullptr;
}
if (points.rbegin()->first + avg_interval < us) {
if (time_points.rbegin()->first + avg_interval < us) {
return nullptr;
}

return (--points.lower_bound(us))->second;
return (--time_points.lower_bound(us))->second;
}

const std::vector<std::shared_ptr<datapoint>>& telemetry::get_all() const
{
return points;
}

std::shared_ptr<telemetry> telemetry::load(const std::string& path, std::optional<double> offset)
Expand Down
5 changes: 4 additions & 1 deletion src/telemetry/telemetry.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,17 @@ class telemetry {
~telemetry() = default;

std::shared_ptr<datapoint> get(double timestamp) const;
const std::vector<std::shared_ptr<datapoint>>& get_all() const;

static std::shared_ptr<telemetry> load(const std::string& path, std::optional<double> offset); // optional offset in seconds

private:
utils::logging::logger log{"telemetry"};

long avg_interval = 0;
std::map<long, std::shared_ptr<datapoint>> points;

std::vector<std::shared_ptr<datapoint>> points;
std::map<long, std::shared_ptr<datapoint>> time_points;
};

} // namespace telemetry
Expand Down
54 changes: 47 additions & 7 deletions src/video/overlay/layout.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
#include "widget/string_widget.h"
#include "widget/value_widget.h"
#include "widget/timestamp_widget.h"
#include "widget/chart_widget.h"
#include "widget/map_widget.h"
#include "utils/logging/logger.h"

#include <string>
Expand Down Expand Up @@ -94,6 +96,10 @@ bool layout_parser::create_widget(pugi::xml_node node, int x_offset, int y_offse
return create_string_widget(node, x_offset, y_offset);
} else if (type == "value") {
return create_value_widget(node, x_offset, y_offset);
} else if (type == "chart") {
return create_chart_widget(node, x_offset, y_offset);
} else if (type == "map") {
return create_map_widget(node, x_offset, y_offset);
}

log.error("Unknown widget type \"{}\"", type);
Expand All @@ -113,41 +119,75 @@ layout_parser::common_text_params layout_parser::text_params(pugi::xml_node node
};
}

layout_parser::common_chart_params layout_parser::chart_params(pugi::xml_node node, int x_offset, int y_offset, bool& out_status)
{
return {
mandatory_attribute(node, "x", out_status).as_int() + x_offset,
mandatory_attribute(node, "y", out_status).as_int() + y_offset,
mandatory_attribute(node, "width", out_status).as_int(),
mandatory_attribute(node, "height", out_status).as_int(),
color_from_string(mandatory_attribute(node, "line-color", out_status).as_string()),
mandatory_attribute(node, "line-width", out_status).as_int(),
color_from_string(mandatory_attribute(node, "point-color", out_status).as_string()),
mandatory_attribute(node, "point-size", out_status).as_int()
};
}

bool layout_parser::create_timestamp_widget(pugi::xml_node node, int x_offset, int y_offset)
{
bool status = true;

common_text_params txt = text_params(node, x_offset, y_offset, status);
auto txt = text_params(node, x_offset, y_offset, status);
std::string format = mandatory_attribute(node, "format", status).as_string();
int utcoffset = mandatory_attribute(node, "utcoffset", status).as_int();

widgets->push_back(std::make_shared<timestamp_widget>(txt.x, txt.y, txt.align, txt.font, txt.color, txt.border_color, txt.border_width, format, utcoffset));

return status;
}

bool layout_parser::create_string_widget(pugi::xml_node node, int x_offset, int y_offset)
{
bool status = true;

common_text_params txt = text_params(node, x_offset, y_offset, status);
auto txt = text_params(node, x_offset, y_offset, status);
std::string text = mandatory_attribute(node, "text", status).as_string();

widgets->push_back(std::make_shared<string_widget>(txt.x, txt.y, txt.align, txt.font, txt.color, txt.border_color, txt.border_width, text));

return status;
}

bool layout_parser::create_value_widget(pugi::xml_node node, int x_offset, int y_offset)
{
bool status = true;
common_text_params txt = text_params(node, x_offset, y_offset, status);

auto txt = text_params(node, x_offset, y_offset, status);
std::string key = mandatory_attribute(node, "key", status).as_string();
int precision = mandatory_attribute(node, "precision", status).as_int();

widgets->push_back(std::make_shared<value_widget>(txt.x, txt.y, txt.align, txt.font, txt.color, txt.border_color, txt.border_width, key, precision));
log.warning("Not yet implemented: layout_parser::create_value_widget");
return true;
return status;
}

bool layout_parser::create_chart_widget(pugi::xml_node node, int x_offset, int y_offset)
{
bool status = true;

auto chrt = chart_params(node, x_offset, y_offset, status);
std::string x_key = mandatory_attribute(node, "x-key", status).as_string();
std::string y_key = mandatory_attribute(node, "y-key", status).as_string();

widgets->push_back(std::make_shared<chart_widget>(chrt.x, chrt.y, chrt.width, chrt.height, chrt.line_color, chrt.line_width, chrt.point_color, chrt.point_size, x_key, y_key));
return status;
}

bool layout_parser::create_map_widget(pugi::xml_node node, int x_offset, int y_offset)
{
bool status = true;

auto chrt = chart_params(node, x_offset, y_offset, status);

widgets->push_back(std::make_shared<map_widget>(chrt.x, chrt.y, chrt.width, chrt.height, chrt.line_color, chrt.line_width, chrt.point_color, chrt.point_size));
return status;
}

pugi::xml_attribute layout_parser::mandatory_attribute(pugi::xml_node node, const std::string& attr_name, bool& out_status)
Expand Down
15 changes: 15 additions & 0 deletions src/video/overlay/layout.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ class layout_parser {

private:
struct common_text_params;
struct common_chart_params;

utils::logging::logger log{"layout::load"};

Expand All @@ -34,8 +35,11 @@ class layout_parser {
bool create_timestamp_widget(pugi::xml_node node, int x_offset, int y_offset);
bool create_string_widget(pugi::xml_node node, int x_offset, int y_offset);
bool create_value_widget(pugi::xml_node node, int x_offset, int y_offset);
bool create_chart_widget(pugi::xml_node node, int x_offset, int y_offset);
bool create_map_widget(pugi::xml_node node, int x_offset, int y_offset);

common_text_params text_params(pugi::xml_node node, int x_offset, int y_offset, bool& out_status);
common_chart_params chart_params(pugi::xml_node node, int x_offset, int y_offset, bool& out_status);
pugi::xml_attribute mandatory_attribute(pugi::xml_node node, const std::string& attr_name, bool& out_status);

std::shared_ptr<layout> widgets;
Expand All @@ -52,6 +56,17 @@ struct layout_parser::common_text_params{
int border_width;
};

struct layout_parser::common_chart_params{
int x;
int y;
int width;
int height;
rgba line_color;
int line_width;
rgba point_color;
int point_size;
};

} // namespace overlay
} // namespace video
} // namespace vgraph
Expand Down
7 changes: 5 additions & 2 deletions src/video/overlay/overlay.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ namespace overlay {

overlay::overlay(std::shared_ptr<layout> lay, std::shared_ptr<telemetry::telemetry> tele, std::pair<int, int> resolution, bool timecode):
tele_(tele),
layout_(*lay),
width(resolution.first),
height(resolution.second)
{
Expand Down Expand Up @@ -49,12 +50,14 @@ void overlay::precache()
{
auto t1 = std::chrono::high_resolution_clock::now();

cairo_t* cr = cairo_create(static_cache);
for (auto w : layout_) {
w->prepare(tele_->get_all());
}

cairo_t* cr = cairo_create(static_cache);
for (auto w : static_widgets_) {
w->draw_static(cr);
}

cairo_destroy(cr);

auto t2 = std::chrono::high_resolution_clock::now();
Expand Down
2 changes: 2 additions & 0 deletions src/video/overlay/overlay.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ class overlay {
int cache_hit = 0;
int cache_miss = 0;

std::vector<std::shared_ptr<widget>> layout_;

std::vector<std::shared_ptr<widget>> static_widgets_;
std::vector<std::shared_ptr<widget>> dynamic_widgets_;
std::shared_ptr<timecode_widget> tc_widget_;
Expand Down
4 changes: 4 additions & 0 deletions src/video/overlay/widget/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ target_sources(vgraph_lib
string_widget.cpp
value_widget.cpp
timestamp_widget.cpp
chart_widget.cpp
map_widget.cpp
timecode_widget.cpp
text_align.cpp
color.cpp
Expand All @@ -16,6 +18,8 @@ target_sources(vgraph_lib
string_widget.h
value_widget.h
timestamp_widget.h
chart_widget.h
map_widget.h
timecode_widget.h
text_align.h
color.h
Expand Down
Loading

0 comments on commit 1b1e7eb

Please sign in to comment.