Skip to content

Commit

Permalink
Merge branch 'master' of github.com:ReproNim/reprostim
Browse files Browse the repository at this point in the history
* 'master' of github.com:ReproNim/reprostim:
  Regenerated Singularity/Dockerfile, #122
  Add sound dependencies to psychopy singularity container (system and python packages).
  Notes for recorded video file size with videocapture/ffmpeg, #68
  Extend parse_wQR.py script with INFO mode to dump videos information like duration, rate, size in JSON format, #104
  Increase ffmpeg bitrate/buffers in 4 times, closer to standard video quality, #68
  Updated docs, optionally wrap executions of ffmpeg with duct #113
  Added version information to reprostim-videocapture JSON metadata logs for informational purposes, #114
  Readme notes to for con/duct setup, #113
  Rename info/usage.json files produced by con/duct on ffmpeg process exit, #113
  optionally wrap executions of ffmpeg with duct #113
  Template for con/duct command wrapper, #113
  Configuration stub/placeholder for con/duct, #113
  Auto-recovery of ffmpeg process in reprostim-videocapture utility #114
  Auto-recovery of ffmpeg process in reprostim-videocapture utility #114
  Auto-recovery of ffmpeg process in reprostim-videocapture utility #114
  Fixed issue - upon reloading config file prior main log file got overwritten, #112
  CPU/resources usage statistics for ffmpeg with options we used before, #68
  videocapture configuration and research to fix drop frames and encoding performance issues, #68
  Generate QR info script to work with ReproNim session structure from https://github.com/ReproNim/reproflow-data-sync, #96
  Generate QR info script to work with ReproNim session structure from https://github.com/ReproNim/reproflow-data-sync, #96
  • Loading branch information
yarikoptic committed Nov 27, 2024
2 parents abc09f6 + 705b900 commit bb53383
Show file tree
Hide file tree
Showing 20 changed files with 896 additions and 33 deletions.
14 changes: 12 additions & 2 deletions Capture/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,19 @@ USB Capture devices and save it to a file. It is a part of the ReproStim project

## Dependencies

On Debian:
### On Debian:

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:
Optionally, in case `con/duct` tool is used and `conduct_opts.enabled` is set to true in reprostim-videocapture `config.yaml`:

apt-get install -y python3-pip
python3 -m venv venv
source venv/bin/activate
pip install con-duct
duct --version

### Project requirements:
- OS Linux
- g++ (C++20)
- CMake 3.10+
Expand All @@ -29,6 +37,8 @@ Project requirements:
- catch2
- v4l-utils
- ffmpeg
- pip+con/duct (optional)




Expand Down
12 changes: 12 additions & 0 deletions Capture/capturelib/include/reprostim/CaptureApp.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,13 @@ namespace reprostim {
}
#endif // _NOTIFY_REPROMON

// optional con/duct options
struct ConductOpts {
bool enabled = false;
std::string cmd;
std::string duct_bin;
};

struct FfmpegOpts {
std::string a_fmt;
std::string a_nchan;
Expand Down Expand Up @@ -49,6 +56,7 @@ namespace reprostim {
LogLevel session_logger_level = LogLevel::OFF;
std::string session_logger_pattern;
std::string video_device_path_pattern;
ConductOpts conduct_opts;
RepromonOpts repromon_opts;
FfmpegOpts ffm_opts;
};
Expand Down Expand Up @@ -113,6 +121,7 @@ namespace reprostim {
SessionLogger_ptr createSessionLogger(const std::string& name, const std::string& filePath);
void listDevices(const std::string& devices);
virtual bool loadConfig(AppConfig& cfg, const std::string& pathConfig);
virtual void onCaptureIdle();
virtual void onCaptureStart();
virtual void onCaptureStop(const std::string& message);
virtual bool onLoadConfig(AppConfig& cfg, const std::string& pathConfig, YAML::Node doc);
Expand All @@ -123,6 +132,9 @@ namespace reprostim {
int run(int argc, char* argv[]);
};

// methods
int checkConduct(const ConductOpts& opts);

// inline methods

inline void CaptureApp::disconnDevAdd(const std::string& devPath) {
Expand Down
39 changes: 38 additions & 1 deletion Capture/capturelib/src/CaptureApp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,24 @@

namespace reprostim {

int checkConduct(const ConductOpts& opts) {
if (!opts.enabled) {
_VERBOSE("Conduct monitoring is disabled");
return EX_OK;
}
std::string cmd = opts.duct_bin + " --version";
std::string res = exec(cmd);
if (res.empty() || !res.starts_with("duct ")) {
_ERROR("con/duct utility not found. Please make sure it's installed with 'pip install con-duct'");
_ERROR(" and configured correctly in config.yaml -> conduct_opts -> duct_bin .");
_ERROR(" COMMAND : " << cmd);
_ERROR(" RESULT : " << res);
return EX_UNAVAILABLE;
}
_VERBOSE("con/duct utility found: " << res);
return EX_OK;
}

void signalHandler(int signum) {
//_INFO("Signal received: " << signum);
if (signum == SIGINT) {
Expand Down Expand Up @@ -190,6 +208,15 @@ namespace reprostim {
opts.out_fmt = node["out_fmt"].as<std::string>();
}

// load conduct_opts
if( doc["conduct_opts"] ) {
YAML::Node node = doc["conduct_opts"];
ConductOpts& opts = cfg.conduct_opts;
opts.enabled = node["enabled"].as<bool>();
opts.cmd = node["cmd"].as<std::string>();
opts.duct_bin = node["duct_bin"].as<std::string>();
}

// load repromon_opts
if( doc["repromon_opts"] ) {
YAML::Node node = doc["repromon_opts"];
Expand Down Expand Up @@ -218,6 +245,9 @@ namespace reprostim {
return this->onLoadConfig(cfg, pathConfig, doc);
}

void CaptureApp::onCaptureIdle() {
}

void CaptureApp::onCaptureStart() {
_INFO("TODO: onCaptureStart");
}
Expand Down Expand Up @@ -299,6 +329,12 @@ namespace reprostim {
return res2;
}

const int res3 = checkConduct(cfg.conduct_opts);
if( res3!=EX_OK ) {
// problem with con/duct configuration or installation
return res3;
}

// start repromon queue
if( cfg.repromon_opts.enabled ) {
fRepromonEnabled = true;
Expand Down Expand Up @@ -462,7 +498,8 @@ namespace reprostim {
else {
if( !vssEquals(vssCur, vssPrev) ) {
onCaptureStop(":\tStopped recording because something changed.");
}
} else
onCaptureIdle(); // hook to check capture cycle
}
}
else {
Expand Down
6 changes: 3 additions & 3 deletions Capture/capturelib/src/CaptureLog.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ namespace reprostim {
{
// Create a logger with two sinks: stdout and file
auto console_sink = std::make_shared<spdlog::sinks::ansicolor_stdout_sink_mt>();
auto file_sink = std::make_shared<spdlog::sinks::basic_file_sink_mt>(filePath, true);
auto file_sink = std::make_shared<spdlog::sinks::basic_file_sink_mt>(filePath, false);

// Create a logger with the two sinks
auto logger = std::make_shared<spdlog::logger>(name,
Expand Down Expand Up @@ -116,8 +116,8 @@ namespace reprostim {
spdlog::register_logger(logger);

// Redirect stdout to the file
freopen(filePath.c_str(), "w", stdout);
freopen(filePath.c_str(), "w", stderr);
freopen(filePath.c_str(), "a", stdout);
freopen(filePath.c_str(), "a", stderr);
//logger->sinks().push_back(console_sink);
g_pGlobalLogger = logger;
}
Expand Down
60 changes: 60 additions & 0 deletions Capture/research/ffmpeg_enc/ffmpeg_enc.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
#!/bin/bash

#set VDEV=/dev/video1
#set MKV=./1.mkv

#echo "Test 1"

#rm $MKV
#ffmpeg -f v4l2 -input_format yuyv422 -framerate 60 -video_size 1920x1080 -thread_queue_size 40960 -i $VDEV -c:v libx264 -flush_packets 1 -an $MKV

#ffmpeg -f alsa -ac 2 -thread_queue_size 4096 -i hw:1,1
# -f v4l2 -input_format yuyv422 -framerate 60 -video_size 1920x1080 -thread_queue_size 4096
# -i /dev/video0 -c:v libx264 -flush_packets 1
# -acodec aac ./1.mkv 2>&1

# Simple 15 sec video capture with no audio
#echo "Test 001"
#rm output001.mp4
#/usr/bin/time -v ffmpeg -f v4l2 -framerate 60 -video_size 1920x1080 -t 15 -i /dev/video0 -an output001.mp4

# Simple 15 sec video capture with no audio and x264 codec
#echo "Test 002"
#rm output002.mp4
#/usr/bin/time -v ffmpeg -f v4l2 -framerate 60 -video_size 1920x1080 -t 15 -i /dev/video0 -c:v libx264 -an output002.mp4

# Simple video capture with audio and video and start time set to 0 for both audio and video
#echo "Test 003"
#rm output003.mp4
#ffmpeg -f alsa -ac 2 -thread_queue_size 4096 -i hw:1,1 -f v4l2 -framerate 60 -video_size 1920x1080 -i /dev/video0 -c:v libx264 -acodec aac -vf setpts=PTS-STARTPTS -af asetpts=PTS-STARTPTS output003.mp4

# video capture with x264 optimizations: fast 2M bit rate
#echo "Test 004"
#rm output004.mp4
#/usr/bin/time -v ffmpeg -f alsa -t 15 -ac 2 -thread_queue_size 4096 -i hw:1,1 -f v4l2 -t 15 -framerate 60 -video_size 1920x1080 -i /dev/video0 -c:v libx264 -b:v 2M -preset fast -acodec aac -vf setpts=PTS-STARTPTS -af asetpts=PTS-STARTPTS output004.mp4

# video capture with x264 optimizations: ultrafast
#echo "Test 005"
#rm output005.mp4
#/usr/bin/time -v ffmpeg -f alsa -t 15 -ac 2 -thread_queue_size 4096 -i hw:1,1 -f v4l2 -t 15 -framerate 60 -video_size 1920x1080 -i /dev/video0 -c:v libx264 -b:v 2M -preset ultrafast -acodec aac -vf setpts=PTS-STARTPTS -af asetpts=PTS-STARTPTS output005.mp4

# video capture with x264 optimizations: ultrafast, crf=18 r-60?
#echo "Test 006"
#rm output006.mp4
#/usr/bin/time -v ffmpeg -f alsa -t 15 -ac 2 -thread_queue_size 4096 -i hw:1,1 -f v4l2 -t 15 -framerate 60 -video_size 1920x1080 -i /dev/video0 -c:v libx264 -r 60 -b:v 2M -preset ultrafast -crf 18 -acodec aac -vf setpts=PTS-STARTPTS -af asetpts=PTS-STARTPTS output006.mp4

# video capture with x264 optimizations: ultrafast, crf=18 zerolatency
# 470M/hour
#echo "Test 007"
#rm output007.mp4
#/usr/bin/time -v ffmpeg -f alsa -t 600 -ac 2 -thread_queue_size 4096 -i hw:1,1 -f v4l2 -t 600 -framerate 60 -video_size 1920x1080 -i /dev/video0 -c:v libx264 -flush_packets 1 -preset ultrafast -crf 18 -r 60 -tune zerolatency -b:v 2M -maxrate 2M -bufsize 4M -acodec aac -vf setpts=PTS-STARTPTS -af asetpts=PTS-STARTPTS output007.mp4

# video capture with x264 optimizations: ultrafast, crf=18 zerolatency
#echo "Test 008"
#rm output008.mp4
#/usr/bin/time -v ffmpeg -f alsa -t 15 -ac 2 -thread_queue_size 4096 -i hw:1,1 -f v4l2 -t 15 -framerate 60 -video_size 1920x1080 -i /dev/video0 -c:v libx264 -flush_packets 1 -preset ultrafast -crf 18 -r 60 -tune zerolatency -b:v 2M -maxrate 2M -bufsize 4M -acodec aac -vf setpts=PTS-STARTPTS -af asetpts=PTS-STARTPTS output008.mp4

# video capture similar to initial one we have before changes
echo "Test 009"
rm output009.mp4
/usr/bin/time -v ffmpeg -f alsa -t 15 -ac 2 -thread_queue_size 4096 -i hw:1,1 -f v4l2 -t 15 -input_format yuyv422 -framerate 60 -video_size 1920x1080 -thread_queue_size 4096 -i /dev/video0 -c:v libx264 -flush_packets 1 output009.mkv
Loading

0 comments on commit bb53383

Please sign in to comment.