Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

added unit tests #15

Merged
merged 3 commits into from
Nov 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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