From 61edd2954ec555d06fcaaa8243060cb1fbbaefc6 Mon Sep 17 00:00:00 2001 From: Vadim Melnik Date: Mon, 29 Jan 2024 15:33:29 +0200 Subject: [PATCH] ScreenCapture added "interval_ms" options (work in progress). --- Capture/capturelib/include/CaptureLib.h | 8 +++++ Capture/screencapture/RecordingThread.cpp | 37 ++++++++++++++++++----- Capture/screencapture/RecordingThread.h | 1 + Capture/screencapture/ScreenCapture.cpp | 17 ++++++----- Capture/screencapture/ScreenCapture.h | 1 + Capture/screencapture/config.yaml | 9 ++++-- 6 files changed, 56 insertions(+), 17 deletions(-) diff --git a/Capture/capturelib/include/CaptureLib.h b/Capture/capturelib/include/CaptureLib.h index 02aa3b0..7be1447 100644 --- a/Capture/capturelib/include/CaptureLib.h +++ b/Capture/capturelib/include/CaptureLib.h @@ -103,5 +103,13 @@ namespace reprostim { std::string vssToString(const MWCAP_VIDEO_SIGNAL_STATUS &vsStatus); + // inline functions + inline long long currentTimeMs() { + return std::chrono::duration_cast( + std::chrono::system_clock::now().time_since_epoch() + ).count(); + } + + } #endif //REPROSTIM_CAPTURELIB_H diff --git a/Capture/screencapture/RecordingThread.cpp b/Capture/screencapture/RecordingThread.cpp index 4c3a6b6..ec96f22 100644 --- a/Capture/screencapture/RecordingThread.cpp +++ b/Capture/screencapture/RecordingThread.cpp @@ -65,7 +65,7 @@ int recordScreens(const RecordingParams& rp, std::atomic& terminated) { fmt.fmt.pix.width = rp.cx; // 640; fmt.fmt.pix.height = rp.cy; // 480; if (ioctl(fd, VIDIOC_S_FMT, &fmt) == -1) { - _ERROR("Failed to set format"); + _ERROR("Failed to set v4l2 format: cx=" << rp.cx << ", cy=" << rp.cy); close(fd); return -1; } @@ -113,18 +113,20 @@ int recordScreens(const RecordingParams& rp, std::atomic& terminated) { unsigned char* previousFrame = new unsigned char[buf.length]; unsigned char* currentFrame = new unsigned char[buf.length]; int nFrame = 0; + bool fSave = false; + long long nextSaveTime = currentTimeMs() + rp.intervalMs; std::string start_ts = getTimeStr(); std::filesystem::path sessionPath = std::filesystem::path(rp.outPath) / (start_ts + "_"); if( !std::filesystem::exists(sessionPath) ) { - _INFO("Create directory: " << sessionPath.string()); + _INFO("Create session " << rp.sessionId << " directory: " << sessionPath.string()); std::filesystem::create_directory(sessionPath); } // Capturing and comparing loop while (true) { if( terminated ) { - _INFO("Capture terminated for sessionId=" << rp.sessionId); + _INFO("Capture terminated for session " << rp.sessionId); break; } @@ -146,13 +148,31 @@ int recordScreens(const RecordingParams& rp, std::atomic& terminated) { } nFrame++; + fSave = false; + + // always save first frame + if( nFrame==1 ) { + fSave = true; + _VERBOSE("Save frame: first frame"); + } + + // save frame when difference is above threshold int difference = calcFrameDiff(currentFrame, previousFrame, buf.length); + if (difference > rp.threshold ) { + fSave = true; + _VERBOSE("Save frame: difference=" << difference); + } + + // check obligatory save interval + if( rp.intervalMs>0 && currentTimeMs() > nextSaveTime ) { + fSave = true; + _VERBOSE("Save frame: interval"); + } - if (difference > rp.threshold || nFrame==1) { - std::string ts = getTimeStr(); - _INFO(ts << " change " << difference << " detected"); + if (fSave) { + nextSaveTime = currentTimeMs() + rp.intervalMs; - std::string baseName = ts; + std::string baseName = getTimeStr(); std::filesystem::path basePath = sessionPath / baseName; if (rp.dumpRawFrame) { @@ -199,7 +219,8 @@ int recordScreens(const RecordingParams& rp, std::atomic& terminated) { std::string end_ts = getTimeStr(); std::filesystem::path sessionPath2 = sessionPath; sessionPath2.replace_filename(start_ts+"_"+end_ts); - _INFO("Rename session directory: " << sessionPath.string() << " -> " << sessionPath2.string()); + _INFO("Rename session " << rp.sessionId << " directory: " + << sessionPath.string() << " -> " << sessionPath2.string()); std::filesystem::rename(sessionPath, sessionPath2); _VERBOSE("recordScreens leave, sessionId=" << rp.sessionId); diff --git a/Capture/screencapture/RecordingThread.h b/Capture/screencapture/RecordingThread.h index 357529a..c71d838 100644 --- a/Capture/screencapture/RecordingThread.h +++ b/Capture/screencapture/RecordingThread.h @@ -15,6 +15,7 @@ struct RecordingParams { std::string outPath; std::string videoDevPath; bool dumpRawFrame; + int intervalMs; }; diff --git a/Capture/screencapture/ScreenCapture.cpp b/Capture/screencapture/ScreenCapture.cpp index c1ae150..bf3e0ad 100644 --- a/Capture/screencapture/ScreenCapture.cpp +++ b/Capture/screencapture/ScreenCapture.cpp @@ -1,6 +1,5 @@ #include #include -#include #include #include #include @@ -18,8 +17,10 @@ inline void rtSafeDelete(RecordingThread* &prt) { } if( !prt->isRunning() ) { delete prt; + } else { + // NOTE: memory-leaks are possible in rare conditions + _INFO("Failed to stop recording thread: " << prt); } - // NOTE: memory-leaks are possible in rare conditions prt = nullptr; } } @@ -42,7 +43,7 @@ ScreenCaptureApp::~ScreenCaptureApp() { void ScreenCaptureApp::onCaptureStart() { g_activeSessionId.fetch_add(1); int sessionId = g_activeSessionId; - _INFO("Start recording snapshots, sessionId=" << sessionId); + _INFO("Start recording snapshots in session " << sessionId); SLEEP_MS(200); recording = 1; @@ -57,7 +58,8 @@ void ScreenCaptureApp::onCaptureStart() { m_scOpts.threshold, opts.outPath, targetVideoDevPath, - m_scOpts.dump_raw + m_scOpts.dump_raw, + m_scOpts.interval_ms }); m_prtCur->start(); @@ -65,8 +67,7 @@ void ScreenCaptureApp::onCaptureStart() { void ScreenCaptureApp::onCaptureStop(const std::string& message) { if( recording>0 ) { - int sessionId = g_activeSessionId.fetch_add(1); - _INFO("Stop recording snapshots. " << sessionId); + _INFO("Stop recording snapshots for session " << g_activeSessionId ); rtSafeDelete(m_prtPrev); m_prtPrev = m_prtCur; rtSafeDelete(m_prtPrev); @@ -80,10 +81,12 @@ bool ScreenCaptureApp::onLoadConfig(AppConfig &cfg, const std::string &pathConfi if( doc["sc_opts"] ) { YAML::Node node = doc["sc_opts"]; m_scOpts.dump_raw = node["dump_raw"].as(); + m_scOpts.interval_ms = node["interval_ms"].as(); m_scOpts.threshold = node["threshold"].as(); } else { - m_scOpts.threshold = 0; m_scOpts.dump_raw = false; + m_scOpts.interval_ms = 0; + m_scOpts.threshold = 0; } return true; } diff --git a/Capture/screencapture/ScreenCapture.h b/Capture/screencapture/ScreenCapture.h index 3bb65c1..cd69e6a 100644 --- a/Capture/screencapture/ScreenCapture.h +++ b/Capture/screencapture/ScreenCapture.h @@ -11,6 +11,7 @@ using namespace reprostim; // Specific options for ScreenCaptureApp struct ScreenCaptureOpts { bool dump_raw; + int interval_ms; int threshold; }; diff --git a/Capture/screencapture/config.yaml b/Capture/screencapture/config.yaml index 2c03055..e51f8ff 100644 --- a/Capture/screencapture/config.yaml +++ b/Capture/screencapture/config.yaml @@ -22,9 +22,14 @@ video_device_path_pattern: "/dev/video*" sc_opts: # Specifies diff threshold to detect changes in the screen threshold: 400000 - # bool, specifies whether to dump raw frames to disk along with - # PNG screenshots. Useful for debugging. + # bool, specifies whether to dump raw frames to disk along + # with PNG screenshots. Useful for debugging. dump_raw: false + # Specifies obligatory snapshot capture interval in ms. When + # value is greater than 0 , then snapshot will be captured + # at least every specified period. + interval_ms: 0 +