]> git.sesse.net Git - nageru/commitdiff
Make for somewhat cleaner shutdown.
authorSteinar H. Gunderson <sgunderson@bigfoot.com>
Mon, 1 Oct 2018 20:02:25 +0000 (22:02 +0200)
committerSteinar H. Gunderson <sgunderson@bigfoot.com>
Mon, 1 Oct 2018 20:02:25 +0000 (22:02 +0200)
jpeg_frame_view.cpp
jpeg_frame_view.h
main.cpp

index ef1cded69d9dc98fcf4d26864c6ac3eef76bd667..bc71d00a570e4372a0a679f4f22f04c0b1810a99 100644 (file)
@@ -44,12 +44,14 @@ struct LRUFrame {
        size_t last_used;
 };
 
+thread JPEGFrameView::jpeg_decoder_thread;
 mutex cache_mu;
 map<JPEGID, LRUFrame, JPEGIDLexicalOrder> cache;  // Under cache_mu.
 condition_variable any_pending_decodes, cache_updated;
 deque<pair<JPEGID, JPEGFrameView *>> pending_decodes;  // Under cache_mu.
 atomic<size_t> event_counter{0};
 extern QGLWidget *global_share_widget;
+extern atomic<bool> should_quit;
 
 shared_ptr<Frame> decode_jpeg(const string &filename)
 {
@@ -193,20 +195,21 @@ shared_ptr<Frame> decode_jpeg_with_cache(JPEGID id, CacheMissBehavior cache_miss
        return frame;
 }
 
-void jpeg_decoder_thread()
+void jpeg_decoder_thread_func()
 {
        size_t num_decoded = 0, num_dropped = 0;
 
        pthread_setname_np(pthread_self(), "JPEGDecoder");
-       for ( ;; ) {
+       while (!should_quit.load()) {
                JPEGID id;
                JPEGFrameView *dest;
                CacheMissBehavior cache_miss_behavior = DECODE_IF_NOT_IN_CACHE;
                {
                        unique_lock<mutex> lock(cache_mu);  // TODO: Perhaps under another lock?
                        any_pending_decodes.wait(lock, [] {
-                               return !pending_decodes.empty();
+                               return !pending_decodes.empty() || should_quit.load();
                        });
+                       if (should_quit.load()) break;
                        id = pending_decodes.front().first;
                        dest = pending_decodes.front().second;
                        pending_decodes.pop_front();
@@ -229,8 +232,9 @@ void jpeg_decoder_thread()
                        // put directly into the cache from VideoStream.
                        unique_lock<mutex> lock(cache_mu);
                        cache_updated.wait(lock, [id] {
-                               return cache.count(id) != 0;
+                               return cache.count(id) != 0 || should_quit.load();
                        });
+                       if (should_quit.load()) break;
                        found_in_cache = true;  // Don't count it as a decode.
 
                        auto it = cache.find(id);
@@ -267,6 +271,12 @@ void jpeg_decoder_thread()
        }
 }
 
+void JPEGFrameView::shutdown()
+{
+       any_pending_decodes.notify_all();
+       jpeg_decoder_thread.join();
+}
+
 JPEGFrameView::JPEGFrameView(QWidget *parent)
        : QGLWidget(parent, global_share_widget) {
 }
@@ -304,7 +314,7 @@ void JPEGFrameView::initializeGL()
        static once_flag once;
        call_once(once, [] {
                resource_pool = new ResourcePool;
-               std::thread(&jpeg_decoder_thread).detach();
+               jpeg_decoder_thread = std::thread(jpeg_decoder_thread_func);
        });
 
        ImageFormat inout_format;
index 7c41b78b384e3fe863e57828ebafcce25e42d597..d0cd47c200833a961469fd0b1522f3c928268d1d 100644 (file)
@@ -11,6 +11,7 @@
 #include <movit/ycbcr_input.h>
 
 #include <memory>
+#include <thread>
 
 #include "jpeg_frame.h"
 
@@ -44,6 +45,8 @@ public:
        void setDecodedFrame(std::shared_ptr<Frame> frame);
        void set_overlay(const std::string &text);  // Blank for none.
 
+       static void shutdown();
+
 signals:
        void clicked();
 
@@ -72,6 +75,8 @@ private:
        bool overlay_input_needs_refresh = false;
 
        int gl_width, gl_height;
+
+       static std::thread jpeg_decoder_thread;
 };
 
 #endif  // !defined(_JPEG_FRAME_VIEW_H)
index 42b1867dfb82e061d98ab1d12f62c0ba035e510a..dc80bc2edcc3e6ff24efc2033344ca149998ad23 100644 (file)
--- a/main.cpp
+++ b/main.cpp
@@ -4,6 +4,7 @@
 #include <stdint.h>
 #include <sys/types.h>
 
+#include <atomic>
 #include <chrono>
 #include <condition_variable>
 #include <memory>
@@ -37,7 +38,8 @@ extern "C" {
 using namespace std;
 using namespace std::chrono;
 
-std::mutex RefCountedGLsync::fence_lock;
+mutex RefCountedGLsync::fence_lock;
+atomic<bool> should_quit{false};
 
 int64_t start_pts = -1;
 
@@ -101,12 +103,18 @@ int main(int argc, char **argv)
        MainWindow mainWindow;
        mainWindow.show();
 
+       init_jpeg_vaapi();
+
        load_existing_frames();
-       thread(record_thread_func).detach();
+       thread record_thread(record_thread_func);
 
-       init_jpeg_vaapi();
+       int ret = app.exec();
 
-       return app.exec();
+       should_quit = true;
+       record_thread.join();
+       JPEGFrameView::shutdown();
+
+       return ret;
 }
 
 void load_existing_frames()
@@ -163,13 +171,16 @@ int record_thread_func()
        int64_t last_pts = -1;
        int64_t pts_offset;
 
-       for ( ;; ) {
+       while (!should_quit.load()) {
                AVPacket pkt;
                unique_ptr<AVPacket, decltype(av_packet_unref)*> pkt_cleanup(
                        &pkt, av_packet_unref);
                av_init_packet(&pkt);
                pkt.data = nullptr;
                pkt.size = 0;
+
+               // TODO: Make it possible to abort av_read_frame() (use an interrupt callback);
+               // right now, should_quit will be ignored if it's hung on I/O.
                if (av_read_frame(format_ctx.get(), &pkt) != 0) {
                        break;
                }