From 558a8af6c1177384fdad65aeb7fd72a442328343 Mon Sep 17 00:00:00 2001
From: Tristan Walter <twalter@orn.mpg.de>
Date: Fri, 30 Oct 2020 15:37:40 +0100
Subject: [PATCH] * fixing some minor threading issues

---
 Application/CMakeLists.txt              |  4 +-
 Application/src/tracker/VideoOpener.cpp | 78 ++++++++++++++++---------
 Application/src/tracker/VideoOpener.h   |  6 +-
 3 files changed, 54 insertions(+), 34 deletions(-)

diff --git a/Application/CMakeLists.txt b/Application/CMakeLists.txt
index 2e10e98..3aad1e3 100644
--- a/Application/CMakeLists.txt
+++ b/Application/CMakeLists.txt
@@ -841,8 +841,8 @@ if(${TREX_BUILD_OPENCV})
             -DWITH_FFMPEG:BOOL=${WITH_FFMPEG}
             -DWITH_MSMF:BOOL=FALSE
             -DWITH_IPP:BOOL=FALSE
-	    -DWITH_GTK:BOOL=FALSE
-	    -DWITH_CAIRO:BOOL=FALSE
+            -DWITH_GTK:BOOL=FALSE
+            -DWITH_CAIRO:BOOL=FALSE
             -DWITH_PNG:BOOL=TRUE
             -DBUILD_PERF_TESTS:BOOL=FALSE
             -DBUILD_opencv_apps:BOOL=FALSE
diff --git a/Application/src/tracker/VideoOpener.cpp b/Application/src/tracker/VideoOpener.cpp
index 830d9e5..7ec37f8 100644
--- a/Application/src/tracker/VideoOpener.cpp
+++ b/Application/src/tracker/VideoOpener.cpp
@@ -434,51 +434,73 @@ VideoOpener::BufferedVideo::BufferedVideo(const file::Path& path) : _path(path)
 
 VideoOpener::BufferedVideo::~BufferedVideo() {
     _terminate = true;
-    _terminate_background = true;
     
     if(_update_thread)
         _update_thread->join();
-    if(_background_thread)
-        _background_thread->join();
     
-    _background_video = nullptr;
+    {
+        std::lock_guard guard(_background_mutex);
+        _terminate_background = true;
+        
+        if(_background_thread)
+            _background_thread->join();
+    }
 }
 
 void VideoOpener::BufferedVideo::restart_background() {
-    _terminate_background = true;
-    if(_background_thread)
-        _background_thread->join();
-    
-    _terminate_background = false;
-    
-    std::lock_guard guard(_frame_mutex);
-    cv::Mat img;
-    _background_video->frame(0, img);
-    if(max(img.cols, img.rows) > 500)
-        resize_image(img, 500 / double(max(img.cols, img.rows)));
-    
-    _background_video_index = 0;
-    _accumulator = std::make_unique<AveragingAccumulator<>>(TEMP_SETTING(averaging_method).value<averaging_method_t::Class>());
-    _accumulator->add(img);
+    {
+        std::lock_guard guard(_background_mutex);
+        if(_background_thread)
+            _previous_background_thread = std::move(_background_thread);
+    }
     
     _background_thread = std::make_unique<std::thread>([this](){
+        { // close old background task, if present
+            std::lock_guard guard(_background_mutex);
+            if(_previous_background_thread) {
+                _terminate_background = true;
+                _previous_background_thread->join();
+                _previous_background_thread = nullptr;
+            }
+            _terminate_background = false;
+        }
+        
+        std::unique_ptr<VideoSource> background_video;
+        uint64_t background_video_index = 0;
+        std::unique_ptr<AveragingAccumulator<>> accumulator;
+        
+        { // open video and load first frame
+            background_video = std::make_unique<VideoSource>(_path.str());
+            
+            std::lock_guard guard(_frame_mutex);
+            cv::Mat img;
+            background_video->frame(0, img);
+            if(max(img.cols, img.rows) > 500)
+                resize_image(img, 500 / double(max(img.cols, img.rows)));
+            
+            background_video_index = 0;
+            accumulator = std::make_unique<AveragingAccumulator<>>(TEMP_SETTING(averaging_method).value<averaging_method_t::Class>());
+            accumulator->add(img);
+        }
+        
         _terminated_background_task = false;
         
-        int step = max(1, int(_background_video->length() / max(2.0, double(TEMP_SETTING(average_samples).value<int>()))));
+        int step = max(1, int(background_video->length() / max(2.0, double(TEMP_SETTING(average_samples).value<int>()))));
         cv::Mat flt, img;
         _number_samples = 0;
         
-        while(!_terminate_background && _background_video_index+1+step < _background_video->length()) {
-            _background_video_index += step;
+        while(!_terminate_background && background_video_index+1+step < background_video->length())
+        {
+            background_video_index += step;
             _number_samples += 1;
             
-            _background_video->frame(_background_video_index, img);
+            background_video->frame(background_video_index, img);
             if(max(img.cols, img.rows) > 500)
                 resize_image(img, 500 / double(max(img.cols, img.rows)));
             
-            _accumulator->add(img);
+            accumulator->add(img);
             
-            auto image = _accumulator->finalize();
+            auto image = accumulator->finalize();
             
             std::lock_guard guard(_frame_mutex);
             _background_copy = std::move(image);
@@ -494,6 +516,7 @@ void VideoOpener::BufferedVideo::open(std::function<void(const bool)>&& callback
         int64_t playback_index = 0;
         Timer video_timer;
         double seconds_between_frames = 0;
+        static std::mutex _gpu_mutex; // in case multiple videos are still "open"
         
         cv::Mat local;
         gpuMat background_image;
@@ -503,12 +526,9 @@ void VideoOpener::BufferedVideo::open(std::function<void(const bool)>&& callback
             {
                 std::lock_guard guard(_video_mutex);
                 _video = std::make_unique<VideoSource>(_path.str());
-                
                 _video->frame(0, local);
                 local.copyTo(img);
                 
-                _background_video = std::make_unique<VideoSource>(_path.str());
-                
                 playback_index = 0;
                 video_timer.reset();
                 
@@ -541,6 +561,8 @@ void VideoOpener::BufferedVideo::open(std::function<void(const bool)>&& callback
                     _video->frame((size_t)playback_index, local);
                     
                     if(_number_samples.load() > 1) {
+                        std::lock_guard gpu_guard(_gpu_mutex);
+                        
                         local.copyTo(img);
                         if(max(img.cols, img.rows) > 500)
                             resize_image(img, 500 / double(max(img.cols, img.rows)));
diff --git a/Application/src/tracker/VideoOpener.h b/Application/src/tracker/VideoOpener.h
index 5099670..5d88dee 100644
--- a/Application/src/tracker/VideoOpener.h
+++ b/Application/src/tracker/VideoOpener.h
@@ -28,11 +28,7 @@ public:
     struct BufferedVideo {
         file::Path _path;
         std::unique_ptr<VideoSource> _video;
-        std::unique_ptr<VideoSource> _background_video;
         std::unique_ptr<Image> _background_copy;
-        std::unique_ptr<AveragingAccumulator<>> _accumulator;
-        //uint64_t _background_samples = 0;
-        uint64_t _background_video_index = 0;
         
         std::atomic<bool> _terminated_background_task = true;
         std::atomic<size_t> _number_samples = 0;
@@ -40,6 +36,8 @@ public:
         std::mutex _frame_mutex;
         std::mutex _video_mutex;
         
+        std::mutex _background_mutex;
+        std::unique_ptr<std::thread> _previous_background_thread;
         std::unique_ptr<Image> _cached_frame;
         std::atomic<bool> _terminate = false, _terminate_background = false;
         
-- 
GitLab