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

Integrate reprostim-videocapture application with ReproNim/repromon feedback screen #80

Merged
merged 17 commits into from
Apr 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
3495572
Created "repromon_opts" section in reprostim-***capture app configura…
vmdocua Mar 11, 2024
b8e8962
TaskQueue<> prototype based on single WorkerThread<> executor template.
vmdocua Mar 11, 2024
6d36144
Setup basic repromon message queue prototype implementation.
vmdocua Mar 12, 2024
7f396da
Provide build type information (Release/Debug/etc) in version info.
vmdocua Mar 12, 2024
f5b55b2
Provide build type information (Release/Debug/etc) in version info.
vmdocua Mar 12, 2024
de726ca
Add libcurl and nlohmann/json dependency to the capture projects (to …
vmdocua Mar 12, 2024
04f75b6
Common REST client specific to reprostim tasks (libcurl+nlohmann/json).
vmdocua Mar 16, 2024
94b17c8
Organize and unify timestamp data type in reprostim terms (common and…
vmdocua Mar 17, 2024
1885894
Organize and unify timestamp data type in reprostim terms (common and…
vmdocua Mar 17, 2024
618cd44
Misc tasks: const modifier cosmetics in capturelib.
vmdocua Mar 17, 2024
f570a93
Misc tasks: stream operators.
vmdocua Mar 18, 2024
ad3d604
Misc tasks: stream operators.
vmdocua Mar 18, 2024
c412264
Normalize repromon REST call logs and provide detailed info.
vmdocua Mar 18, 2024
99ce7fb
Expand macros API and time to string helpers, (WiP #81).
vmdocua Mar 20, 2024
1f9e3cb
Make videos file path configurable in reprostim-videocapture, #81.
vmdocua Mar 21, 2024
957afce
Make videos file path configurable in reprostim-videocapture, #81.
vmdocua Apr 4, 2024
bb6740a
Closes PR #81.
vmdocua Apr 17, 2024
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
2 changes: 1 addition & 1 deletion .github/workflows/ccpp.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ jobs:
- name: Install build dependencies
run: |
sudo apt update
sudo apt install -y libyaml-cpp-dev libspdlog-dev catch2 libasound2-dev libv4l-dev libudev-dev libopencv-dev cmake g++
sudo apt install -y libyaml-cpp-dev libspdlog-dev catch2 libasound2-dev libv4l-dev libudev-dev libopencv-dev libcurl4-openssl-dev nlohmann-json3-dev cmake g++

- name: Build
run: |
Expand Down
10 changes: 10 additions & 0 deletions Capture/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,11 @@ set(CAPTURE_VERSION_MAJOR 0)
set(CAPTURE_VERSION_MINOR 0)
set(CAPTURE_VERSION_PATCH 0)
set(CAPTURE_VERSION_BUILD 0)
set(CAPTURE_BUILD_TYPE ${CMAKE_BUILD_TYPE})
# Set CAPTURE_BUILD_TYPE to "Release" if it's empty or an empty string
if(NOT CAPTURE_BUILD_TYPE OR CAPTURE_BUILD_TYPE STREQUAL "")
set(CAPTURE_BUILD_TYPE "Release")
endif()

# load version from version.txt file if any
if(EXISTS ${CAPTURE_VERSION_FILE})
Expand All @@ -30,6 +35,11 @@ if(EXISTS ${CAPTURE_VERSION_FILE})
endif()

set(CAPTURE_VERSION_STRING "${CAPTURE_VERSION_MAJOR}.${CAPTURE_VERSION_MINOR}.${CAPTURE_VERSION_PATCH}.${CAPTURE_VERSION_BUILD}")
# Append "d" to CAPTURE_VERSION_STRING if build type is Debug
if(CAPTURE_BUILD_TYPE STREQUAL "Debug")
set(CAPTURE_VERSION_STRING "${CAPTURE_VERSION_STRING}d")
endif()

string(TIMESTAMP CAPTURE_VERSION_DATE "%Y-%m-%d %H:%M:%S")
execute_process(
COMMAND git describe --tags --always
Expand Down
4 changes: 3 additions & 1 deletion Capture/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ USB Capture devices and save it to a file. It is a part of the ReproStim project

On Debian:

apt-get install -y ffmpeg libudev-dev libasound-dev libv4l-dev libyaml-cpp-dev libspdlog-dev catch2 v4l-utils libopencv-dev cmake g++
apt-get install -y ffmpeg libudev-dev libasound-dev libv4l-dev libyaml-cpp-dev libspdlog-dev catch2 v4l-utils libopencv-dev libcurl4-openssl-dev nlohmann-json3-dev cmake g++

Project requirements:
- OS Linux
Expand All @@ -24,6 +24,8 @@ Project requirements:
- libyaml-cpp-dev
- libspdlog-dev
- libopencv-dev
- libcurl4-openssl-dev
- nlohmann-json3-dev
- catch2
- v4l-utils
- ffmpeg
Expand Down
3 changes: 3 additions & 0 deletions Capture/capturelib/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ configure_file(${PROJECT_SOURCE_DIR}/include/reprostim/CaptureVer.h.in
add_library(${PROJECT_NAME} STATIC
src/CaptureLib.cpp
src/CaptureLog.cpp
src/CaptureRest.cpp
src/CaptureRepromon.cpp
src/CaptureApp.cpp
include/reprostim/CaptureVer.h.in
)
Expand All @@ -29,5 +31,6 @@ target_link_libraries(${PROJECT_NAME}
v4l2
yaml-cpp
spdlog
curl
fmt
)
41 changes: 32 additions & 9 deletions Capture/capturelib/include/reprostim/CaptureApp.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,24 @@
#define CAPTURE_CAPTUREAPP_H

#include <unistd.h>
#include <optional>
#include "reprostim/CaptureLib.h"
#include "reprostim/CaptureThreading.h"
#include "reprostim/CaptureRepromon.h"
#include "yaml-cpp/yaml.h"

namespace reprostim {

// Macros to define message to be sent to repromon system
#ifndef _NOTIFY_REPROMON
#define _NOTIFY_REPROMON(...) if (fRepromonEnabled) { \
RepromonMessage msg = { __VA_ARGS__ }; \
if( msg.event_on.empty() ) { msg.event_on = getTimeIsoStr(); } \
if( msg.registered_on.empty() ) { msg.registered_on = getTimeIsoStr(); } \
pRepromonQueue->push(msg); \
}
#endif // _NOTIFY_REPROMON

struct FfmpegOpts {
std::string a_fmt;
std::string a_nchan;
Expand All @@ -31,20 +43,21 @@ namespace reprostim {
// App configuration loaded from config.yaml, for
// historical reasons keep names in Python style
struct AppConfig {
std::string device_serial_number;
bool has_device_serial_number = false;
bool session_logger_enabled = false;
LogLevel session_logger_level = LogLevel::OFF;
std::string session_logger_pattern;
std::string video_device_path_pattern;
FfmpegOpts ffm_opts;
std::string device_serial_number;
bool has_device_serial_number = false;
bool session_logger_enabled = false;
LogLevel session_logger_level = LogLevel::OFF;
std::string session_logger_pattern;
std::string video_device_path_pattern;
RepromonOpts repromon_opts;
FfmpegOpts ffm_opts;
};

// App command-line options and args
struct AppOpts {
std::string configPath;
std::string homePath;
std::string outPath;
std::string outPathTempl;
bool verbose = false;
};

Expand All @@ -68,11 +81,18 @@ namespace reprostim {
AppOpts opts;
AppConfig cfg;

// repromon message queue
std::unique_ptr<RepromonQueue> pRepromonQueue;
bool fRepromonEnabled;

// session runtime data
std::string configHash;
std::string frameRate;
std::string init_ts;
std::string outPath;
int recording;
Timestamp tsInit;
std::string init_ts;
Timestamp tsStart;
std::string start_ts;
MWCAP_VIDEO_SIGNAL_STATUS vssCur; // current video signal status
MWCAP_VIDEO_SIGNAL_STATUS vssPrev; // previous video signal status
Expand All @@ -87,6 +107,9 @@ namespace reprostim {

public:
CaptureApp();
~CaptureApp();

std::string createOutPath(const std::optional<Timestamp> &ts = std::nullopt, bool fCreateDir = true);
SessionLogger_ptr createSessionLogger(const std::string& name, const std::string& filePath);
void listDevices();
virtual bool loadConfig(AppConfig& cfg, const std::string& pathConfig);
Expand Down
63 changes: 58 additions & 5 deletions Capture/capturelib/include/reprostim/CaptureLib.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,11 @@
#define SLEEP_SEC(sec) SLEEP_MS(static_cast<int>(sec*1000))
#endif

// current TIMESTAMP value
#ifndef CURRENT_TIMESTAMP
#define CURRENT_TIMESTAMP() std::chrono::system_clock::now()
#endif


#define EX_SYS_BREAK_EXEC 140 /* custom exit code when execution broken by Ctrl+C, SIGINT or similar events */
#define EX_CONFIG_RELOAD 141 /* custom exit code when config.yaml file changed */
Expand All @@ -49,6 +54,17 @@ namespace reprostim {
DB = 2 // not supported yet
};

//////////////////////////////////////////////////////////////////////////
// Typedefs

// Define std::string to std::string dictionary type
using SDict = std::unordered_map<std::string, std::string>;

// define timestamp type in reprostim terms and precision
// because in C++ there is no normal stable built-in timestamp
// type ATM
using Timestamp = std::chrono::system_clock::time_point;

//////////////////////////////////////////////////////////////////////////
// Structs

Expand Down Expand Up @@ -92,12 +108,14 @@ namespace reprostim {

int checkSystem();

std::string chiToString(MWCAP_CHANNEL_INFO &info);
std::string chiToString(const MWCAP_CHANNEL_INFO &info);

std::string exec(const std::string &cmd, bool showStdout = false,
int maxResLen = -1,
std::function<bool()> isTerminated = [](){ return false; });

std::string expandMacros(const std::string &text, const SDict &dict);

bool findTargetVideoDevice(const std::string &serialNumber, VideoDevice &vd);

// returns audio device ALSA path and sound card ALSA name
Expand All @@ -119,24 +137,35 @@ namespace reprostim {
// NOTE: uses by-value result
VDevPath getVideoDevicePathBySerial(const std::string &pattern, const std::string &serial);

std::string getTimeStr();
// Date-time format historically used in reprostim
// e.g. "2024.03.02.12.33.08.006"
std::string getTimeStr(const Timestamp &ts = CURRENT_TIMESTAMP());

// Format date/time with strftime-like pattern
std::string getTimeFormatStr(const Timestamp &ts = CURRENT_TIMESTAMP(),
const std::string &format = "%Y-%m-%d %H:%M:%S");

// ISO 8601 date-time string conversion with microseconds
// precision and "no time-zone" information
// e.g. "2024-03-17T17:13:53.478287"
std::string getTimeIsoStr(const Timestamp &ts = CURRENT_TIMESTAMP());

bool isSysBreakExec();

void listAudioDevices();

std::string mwcSdkVersion();

AudioVolume parseAudioVolume(std::string text);
AudioVolume parseAudioVolume(const std::string text);

void safeMWCloseChannel(HCHANNEL&hChannel);
void safeMWCloseChannel(HCHANNEL &hChannel);

void setAudioInVolumeByCard(const std::string &alsaCardName,
const std::unordered_map<std::string, AudioVolume> &mapNameVolume);

void setSysBreakExec(bool fBreak);

std::string vdToString(VideoDevice &vd);
std::string vdToString(const VideoDevice &vd);

// Video signal status helpers
std::string vssFrameRate(const MWCAP_VIDEO_SIGNAL_STATUS &vss);
Expand All @@ -154,6 +183,30 @@ namespace reprostim {
).count();
}

// get std::string representation of time year in format "YYYY"
inline std::string getTimeYearStr(const Timestamp &ts = CURRENT_TIMESTAMP()) {
return getTimeFormatStr(ts, "%Y");
}

// get std::string representation of time month in format "MM"
inline std::string getTimeMonthStr(const Timestamp &ts = CURRENT_TIMESTAMP()) {
return getTimeFormatStr(ts, "%m");
}

inline std::ostream& operator<<(std::ostream& os, const MWCAP_CHANNEL_INFO &chi) {
os << chiToString(chi);
return os;
}

inline std::ostream& operator<<(std::ostream& os, const MWCAP_VIDEO_SIGNAL_STATUS &vss) {
os << vssToString(vss);
return os;
}

inline std::ostream& operator<<(std::ostream& os, const VideoDevice &vd) {
os << vdToString(vd);
return os;
}

}
#endif //REPROSTIM_CAPTURELIB_H
72 changes: 72 additions & 0 deletions Capture/capturelib/include/reprostim/CaptureRepromon.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
#ifndef CAPTURE_CAPTUREREPROMON_H
#define CAPTURE_CAPTUREREPROMON_H

#include <unistd.h>
#include <nlohmann/json.hpp>
#include "reprostim/CaptureLib.h"
#include "reprostim/CaptureThreading.h"
#include "reprostim/CaptureRest.h"

// Specifies repromon message level IDs
#define REPROMON_INFO 1
#define REPROMON_WARNING 2
#define REPROMON_ERROR 3

namespace reprostim {
using json = nlohmann::json;

// repromon options from config.yaml repromon_opts:
struct RepromonOpts {
bool enabled = false;
std::string api_base_url;
std::string api_key;
bool verify_ssl_cert = true;
//
int data_provider_id;
int device_id;
int message_category_id;
int message_level_id;
};

// repromon parameters passed and available in queue message thread context
struct RepromonParams {
const RepromonOpts opts;
};

// Specifies a repromon message to be sent to the repromon REST API
struct RepromonMessage {
int level;
std::string description;
json payload;
std::string study;
std::string event_on;
std::string registered_on;

friend std::ostream& operator<<(std::ostream& os, const RepromonMessage& msg);
};

// Repromon message queue
_TYPEDEF_TASK_QUEUE(RepromonQueue, RepromonParams, RepromonMessage);

// Queue message handler
void repromonQueueDoTask(RepromonQueue &queue, const RepromonMessage &msg);

// override RepromonQueue::doTask implementation
template<>
inline void RepromonQueue::doTask(const RepromonMessage &msg) {
repromonQueueDoTask(*this, msg);
}

// Repromon message to string stream operator
inline std::ostream& operator<<(std::ostream& os, const RepromonMessage& msg) {
os << "RepromonMessage(level=" << msg.level <<
", description=" << msg.description <<
", payload=" << msg.payload <<
", study=" << msg.study <<
", event_on=" << msg.event_on <<
", registered_on=" << msg.registered_on << ")";
return os;
}

} // reprostim
#endif //CAPTURE_CAPTUREREPROMON_H
Loading
Loading