Skip to content

Commit

Permalink
added unit tests (#15)
Browse files Browse the repository at this point in the history
* added unit tests

* fix ci?

* added more unit tests and optimized+redesigned settings to conform to tests
  • Loading branch information
Mast3rwaf1z authored Nov 28, 2024
1 parent 9a9a19a commit 55af650
Show file tree
Hide file tree
Showing 12 changed files with 199 additions and 88 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ jobs:
runs-on: ubuntu-24.04
steps:
- name: install dependencies
run: sudo apt-get update && sudo apt-get -y install cmake libopencv-dev libspdlog-dev
run: sudo apt-get update && sudo apt-get -y install cmake libopencv-dev libspdlog-dev libargparse-dev
- uses: actions/cache@v4
with:
path: build
Expand All @@ -24,3 +24,5 @@ jobs:
run: cmake -B build && cmake --build build -j4
env:
CXX: g++-13
- name: test
run: ctest --test-dir build
27 changes: 19 additions & 8 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -17,22 +17,33 @@ include_directories(include)
find_package( OpenCV REQUIRED )
include_directories( ${OpenCV_INCLUDE_DIRS} )


# argparse
include(FetchContent)
FetchContent_Declare(
argparse
GIT_REPOSITORY https://github.com/p-ranav/argparse.git
)
FetchContent_MakeAvailable(argparse)
find_package(argparse REQUIRED)

#spdlog
# spdlog
find_package(spdlog REQUIRED)

# catch2
find_package(Catch2 REQUIRED)

add_executable(sender src/Sender.cpp ${PROJECT_IMPLEMENTATIONS})

# Linking
target_link_libraries(sender
${OpenCV_LIBS}
argparse
argparse::argparse
spdlog::spdlog
)

# Tests
enable_testing()
foreach(test ffmpeg utils hyperwall)
add_executable(test_${test} src/test/${test}.cpp ${PROJECT_IMPLEMENTATIONS})
target_link_libraries(test_${test}
${OpenCV_LIBS}
spdlog::spdlog
Catch2::Catch2WithMain
)
add_test(NAME ${test} COMMAND test_${test})
endforeach()
2 changes: 2 additions & 0 deletions flake.nix
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
ffmpeg
cmake
spdlog
argparse
catch2_3
];
};
};
Expand Down
43 changes: 21 additions & 22 deletions include/FFmpeg.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,53 +4,52 @@

#include <opencv2/opencv.hpp>

#include "Settings.hpp"

namespace Hyperwall {

class FFmpeg {
FILE* buffer;
public:
const std::tuple<int, int> resolution;
const std::tuple<int, int> position;
const coordinate resolution;
const coordinate position;
const coordinate dimensions;
const int framerate;
const std::string input;
const std::string bitrate;

constexpr FFmpeg(const std::tuple<int, int>& resolution, const int& framerate, const std::string& bitrate, const std::tuple<int, int>& position) :
resolution(resolution),
framerate(framerate),
bitrate(bitrate),
position(position) {
}

constexpr FFmpeg(const int framerate, const std::string bitrate, const std::tuple<int, int> position) :
resolution(1920, 1080),
framerate(framerate),
bitrate(bitrate),
constexpr FFmpeg(Settings settings, coordinate position) :
resolution(settings.resolution),
dimensions(settings.dimensions),
framerate(settings.framerate),
bitrate(settings.bitrate),
position(position) {

}

constexpr FFmpeg(const std::string bitrate, const std::tuple<int, int> position) :
resolution(1920, 1080),
framerate(60),
bitrate(bitrate),
position(position) {

constexpr FFmpeg(Settings settings) :
resolution(settings.resolution),
dimensions(settings.dimensions),
framerate(settings.framerate),
bitrate(settings.bitrate),
position({0, 0}) {
}

constexpr FFmpeg(const std::tuple<int, int> position) :
constexpr FFmpeg(coordinate position) :
resolution(1920, 1080),
dimensions(2, 2),
framerate(60),
bitrate("1G"),
position(position) {

}

constexpr FFmpeg() :
resolution({1920, 1080}),
resolution(1920, 1080),
dimensions(0, 0),
framerate(60),
bitrate("1G"),
position({0, 0}) {
position(0, 0) {
}
constexpr ~FFmpeg() = default;

Expand Down
21 changes: 8 additions & 13 deletions include/Hyperwall.hpp
Original file line number Diff line number Diff line change
@@ -1,33 +1,28 @@
#pragma once

#include <unordered_map>

#include "FFmpeg.hpp"
#include "Sources/VideoSource.hpp"
#include "Settings.hpp"

namespace Hyperwall {

class HyperFrame {
const int x;
const int y;
const int X;
const int Y;
const int RES_X;
const int RES_Y;
const coordinate position;
const coordinate dimensions;
const coordinate resolution;
FFmpeg ffmpeg;
public:
HyperFrame(const HyperFrame&);
HyperFrame(const int, const int, std::unordered_map<std::string, std::string>, FFmpeg&);
HyperFrame(const coordinate&, Settings, FFmpeg&);
void run(const cv::Mat&);
};

class Hyperwall {
std::unique_ptr<VideoSourceT> source;
std::unordered_map<int, std::unordered_map<int, HyperFrame>> frames;
const int X;
const int Y;
std::vector<HyperFrame> frames;
const coordinate dimensions;
public:
Hyperwall(VideoSourceT&, std::unordered_map<std::string, std::string>);
Hyperwall(VideoSourceT&, Settings);
void run();
};

Expand Down
54 changes: 54 additions & 0 deletions include/Settings.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
#pragma once

#include <tuple>
#include <string>

namespace Hyperwall {

typedef std::tuple<int, int> coordinate;

struct Settings {
public:
const coordinate resolution;
const coordinate dimensions;
const std::string bitrate;
const unsigned int framerate;
constexpr Settings(const coordinate& resolution, const coordinate& dimensions, const std::string bitrate, const unsigned int framerate) :
resolution(resolution),
dimensions(dimensions),
bitrate(bitrate),
framerate(framerate) {
}

constexpr Settings(const coordinate& resolution, const coordinate& dimensions, const std::string bitrate) :
resolution(resolution),
dimensions(dimensions),
bitrate(bitrate),
framerate(60) {

}

constexpr Settings(const coordinate& resolution, const coordinate& dimensions) :
resolution(resolution),
dimensions(dimensions),
bitrate("1G"),
framerate(60) {
}

constexpr Settings(const coordinate& resolution) :
resolution(resolution),
dimensions({2, 2}),
bitrate("1G"),
framerate(60) {
}

constexpr Settings() :
resolution({1920, 1080}),
dimensions({2, 2}),
bitrate("1G"),
framerate(60) {

}
};

}
25 changes: 15 additions & 10 deletions src/Sender.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
#include <filesystem>
#include <spdlog/common.h>
#include <string>
#include <unordered_map>

#include <argparse/argparse.hpp>
#include <opencv2/opencv.hpp>
Expand All @@ -28,7 +27,7 @@ int main(int argc, char* argv[]) {
parser.add_argument("--resolution")
.default_value("1920x1080");
parser.add_argument("--framerate")
.default_value("60");
.default_value(60);
parser.add_argument("--file")
.default_value("file.mp4");
parser.add_argument("--bitrate")
Expand Down Expand Up @@ -57,14 +56,20 @@ int main(int argc, char* argv[]) {
spdlog::set_level(static_cast<spdlog::level::level_enum>(loglevel));
std::cout << "Log level: " << loglevel << std::endl;
spdlog::debug("Generating settings");
std::unordered_map<std::string, std::string> settings({
{"RES_X", split_res(parser.get<std::string>("--resolution"), "x")},
{"RES_Y", split_res(parser.get<std::string>("--resolution"), "y")},
{"X", split_res(parser.get<std::string>("--dimensions"), "x")},
{"Y", split_res(parser.get<std::string>("--dimensions"), "y")},
{"FRAMERATE", parser.get<std::string>("--framerate")},
{"BITRATE", parser.get<std::string>("--bitrate")}
});

Hyperwall::Settings settings(
{
stoi(split_res(parser.get("--resolution"), "x")),
stoi(split_res(parser.get("--resolution"), "y"))
},
{
stoi(split_res(parser.get("--dimensions"), "x")),
stoi(split_res(parser.get("--dimensions"), "y"))
},
parser.get("--bitrate"),
parser.get<int>("--framerate")
);

Hyperwall::Hyperwall hyperwall = [&settings, &parser](std::string mode) {
spdlog::info("Chosen mode: {}", mode);
if(mode == "webcam") {
Expand Down
5 changes: 3 additions & 2 deletions src/impl/FFmpeg.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,13 @@
const void Hyperwall::FFmpeg::open() {
const auto [res_x, res_y] = resolution;
const auto [x, y] = position;
const auto [X, Y] = dimensions;
std::stringstream ss;
ss << "ffmpeg -re -y -f rawvideo -vcodec rawvideo -pix_fmt bgr24 -s "
<< res_x << "x" << res_y
<< res_x/X << "x" << res_y/Y
<< " -r " << framerate
<< " -i - -f mpegts -preset ultrafast -s "
<< res_x << "x" << res_y
<< res_x/X << "x" << res_y/Y
<< " -r " << framerate
<< " -f rtsp -b:v "
<< bitrate
Expand Down
58 changes: 26 additions & 32 deletions src/impl/Hyperwall.cpp
Original file line number Diff line number Diff line change
@@ -1,61 +1,57 @@
#include <spdlog/spdlog.h>
#include <string>
#include <unordered_map>

#include <spdlog/spdlog.h>

#include "Utils.hpp"
#include "FFmpeg.hpp"
#include "Hyperwall.hpp"

Hyperwall::HyperFrame::HyperFrame(const int x, const int y, std::unordered_map<std::string, std::string> settings, FFmpeg& ffmpeg) :
x(x),
y(y),
X(stoi(settings["X"])),
Y(stoi(settings["Y"])),
Hyperwall::HyperFrame::HyperFrame(const coordinate& position, Settings settings, FFmpeg& ffmpeg) :
position(position),
dimensions(settings.dimensions),
ffmpeg(ffmpeg),
RES_X(stoi(settings["RES_X"])),
RES_Y(stoi(settings["RES_Y"])) {
resolution(settings.resolution) {
this->ffmpeg.open();
const auto& [x, y] = position;
spdlog::info("Built HyperFrame: [x: {}, y: {}, uri: {}]", x, y, ffmpeg.uri());
}

Hyperwall::HyperFrame::HyperFrame(const HyperFrame& other) :
x(other.x),
y(other.y),
X(other.X),
Y(other.Y),
ffmpeg(other.ffmpeg),
RES_X(other.RES_X),
RES_Y(other.RES_Y) {
spdlog::debug("Copied hyperframe object at: ({},{}) in {}x{}", x,y,X,Y);
position(other.position),
dimensions(other.dimensions),
resolution(other.resolution),
ffmpeg(other.ffmpeg) {
const auto& [x, y] = position;
const auto& [X, Y] = dimensions;
spdlog::debug("Copied hyperframe object at: ({}) in {}", x,y,X,Y);
}

void Hyperwall::HyperFrame::run(const cv::Mat& image) {
spdlog::debug("Running Hyperframe");
const auto& [x, y] = position;
const auto& [X, Y] = dimensions;
const auto& [res_x, res_y] = resolution;
spdlog::debug("Running Hyperframe: p: {}x{}, d: {}x{}, r: {}x{}", x, y, X, Y, res_x, res_y);
auto start_x = (int)(image.cols * ((0.0 + x)/X));
auto end_x = (int)(image.cols * ((1.0+x)/X));
auto start_y = (int)(image.rows * ((0.0 + y)/Y));
auto end_y = (int)(image.rows * ((1.0+y)/Y));

auto sub_image = image(cv::Range(start_y, end_y), cv::Range(start_x, end_x));
cv::Mat resized_image;
cv::resize(sub_image, resized_image, cv::Size(RES_X/X, RES_Y/Y));
cv::resize(sub_image, resized_image, cv::Size(res_x/X, res_y/Y));
ffmpeg.write(resized_image);
}

Hyperwall::Hyperwall::Hyperwall(VideoSourceT& source, std::unordered_map<std::string, std::string> settings) : source(source.clone()), X(stoi(settings["X"])), Y(stoi(settings["Y"])) {
Hyperwall::Hyperwall::Hyperwall(VideoSourceT& source, Settings settings) :
source(source.clone()),
dimensions(settings.dimensions) {
spdlog::info("Generating hyperwall...");
const auto& [res_x, res_y] = settings.resolution;
const auto& [X, Y] = settings.dimensions;
for(const auto x : Util::range(X)) {
frames.insert({x, {}});
for(const auto y : Util::range(Y)) {
FFmpeg ffmpeg(
{std::stoi(settings["RES_X"])/X, std::stoi(settings["RES_Y"])/Y},
std::stoi(settings["FRAMERATE"]),
settings["BITRATE"],
{x, y}
);
frames[x].insert({y, HyperFrame(x, y, settings, ffmpeg)});
FFmpeg ffmpeg(settings, {x, y});
frames.push_back({{x, y}, settings, ffmpeg});
}
}
};
Expand All @@ -67,10 +63,8 @@ void Hyperwall::Hyperwall::run() {
if (image.rows == 0 || image.cols == 0) {
break;
}
for(auto& [x, x_frames] : frames) {
for(auto& [y, frame] : x_frames) {
frame.run(image);
}
for(auto& frame : frames) {
frame.run(image);
}
}
spdlog::info("Finished hyperwall execution");
Expand Down
Loading

0 comments on commit 55af650

Please sign in to comment.