]> git.sesse.net Git - nageru/commitdiff
Redo frame buffering again.
authorSteinar H. Gunderson <sgunderson@bigfoot.com>
Mon, 23 Nov 2015 00:44:27 +0000 (01:44 +0100)
committerSteinar H. Gunderson <sgunderson@bigfoot.com>
Mon, 23 Nov 2015 00:48:22 +0000 (01:48 +0100)
This partially reverts 86f32b5a in that it removes the exact counting;
however, the system wasn't safe at all (threading, for instance, but
more generally, that the entire state could change between display and
get chain). Put all the state within the chain setup instead.

input_state.h [new file with mode: 0644]
mixer.cpp
mixer.h
theme.cpp
theme.h

diff --git a/input_state.h b/input_state.h
new file mode 100644 (file)
index 0000000..26015ef
--- /dev/null
@@ -0,0 +1,24 @@
+#ifndef _INPUT_STATE_H
+#define _INPUT_STATE_H 1
+
+#include "defs.h"
+#include "ref_counted_frame.h"
+
+struct BufferedFrame {
+       RefCountedFrame frame;
+       unsigned field_number;
+};
+
+// Encapsulates the state of all inputs at any given instant.
+// In particular, this is captured by Theme::get_chain(),
+// so that it can hold on to all the frames it needs for rendering.
+struct InputState {
+       // For each card, the last three frames (or fields), with 0 being the
+       // most recent one. Note that we only need the actual history if we have
+       // interlaced output (for deinterlacing), so if we detect progressive input,
+       // we immediately clear out all history and all entries will point to the same
+       // frame.
+       BufferedFrame buffered_frames[MAX_CARDS][FRAME_HISTORY_LENGTH];
+};
+
+#endif  // !defined(_INPUT_STATE_H)
index 04a35530cc7af36d7681d1aca2ebef695be960e0..b6824d51ef3911034ac700d1a4a2295e3d57fa1b 100644 (file)
--- a/mixer.cpp
+++ b/mixer.cpp
@@ -59,6 +59,22 @@ void convert_fixed24_to_fp32(float *dst, size_t out_channels, const uint8_t *src
        }
 }
 
+void insert_new_frame(RefCountedFrame frame, unsigned field_num, bool interlaced, unsigned card_index, InputState *input_state)
+{
+       if (interlaced) {
+               for (unsigned frame_num = FRAME_HISTORY_LENGTH; frame_num --> 1; ) {  // :-)
+                       input_state->buffered_frames[card_index][frame_num] =
+                               input_state->buffered_frames[card_index][frame_num - 1];
+               }
+               input_state->buffered_frames[card_index][0] = { frame, field_num };
+       } else {
+               for (unsigned frame_num = 0; frame_num < FRAME_HISTORY_LENGTH; ++frame_num) {
+                       input_state->buffered_frames[card_index][frame_num] = { frame, field_num };
+               }
+       }
+}
+
+
 }  // namespace
 
 Mixer::Mixer(const QSurfaceFormat &format, unsigned num_cards)
@@ -528,16 +544,7 @@ void Mixer::thread_func()
                                continue;
 
                        assert(card->new_frame != nullptr);
-                       if (card->new_frame_interlaced) {
-                               for (unsigned frame_num = FRAME_HISTORY_LENGTH; frame_num --> 1; ) {  // :-)
-                                       buffered_frames[card_index][frame_num] = buffered_frames[card_index][frame_num - 1];
-                               }
-                               buffered_frames[card_index][0] = { card->new_frame, card->new_frame_field };
-                       } else {
-                               for (unsigned frame_num = 0; frame_num < FRAME_HISTORY_LENGTH; ++frame_num) {
-                                       buffered_frames[card_index][frame_num] = { card->new_frame, card->new_frame_field };
-                               }
-                       }
+                       insert_new_frame(card->new_frame, card->new_frame_field, card->new_frame_interlaced, card_index, &input_state);
                        check_error();
 
                        // The new texture might still be uploaded,
@@ -551,7 +558,7 @@ void Mixer::thread_func()
                }
 
                // Get the main chain from the theme, and set its state immediately.
-               Theme::Chain theme_main_chain = theme->get_chain(0, pts(), WIDTH, HEIGHT);
+               Theme::Chain theme_main_chain = theme->get_chain(0, pts(), WIDTH, HEIGHT, input_state);
                EffectChain *chain = theme_main_chain.chain;
                theme_main_chain.setup_chain();
 
@@ -600,7 +607,7 @@ void Mixer::thread_func()
                // Set up preview and any additional channels.
                for (int i = 1; i < theme->get_num_channels() + 2; ++i) {
                        DisplayFrame display_frame;
-                       Theme::Chain chain = theme->get_chain(i, pts(), WIDTH, HEIGHT);  // FIXME: dimensions
+                       Theme::Chain chain = theme->get_chain(i, pts(), WIDTH, HEIGHT, input_state);  // FIXME: dimensions
                        display_frame.chain = chain.chain;
                        display_frame.setup_chain = chain.setup_chain;
                        display_frame.ready_fence = fence;
diff --git a/mixer.h b/mixer.h
index 07a31e959fe5a21e2b268ed7f4aad11e0ac2e90a..6d0cbce1593b6da92c4f426668d948c982683921 100644 (file)
--- a/mixer.h
+++ b/mixer.h
@@ -34,6 +34,7 @@
 #include "timebase.h"
 #include "stereocompressor.h"
 #include "filter.h"
+#include "input_state.h"
 
 class H264Encoder;
 class QSurface;
@@ -170,16 +171,6 @@ public:
 
        void reset_meters();
 
-       struct BufferedFrame {
-               RefCountedFrame frame;
-               unsigned field_number;
-       };
-
-       BufferedFrame get_buffered_frame(int card, int history_pos)
-       {
-               return buffered_frames[card][history_pos];
-       }
-
 private:
        void bm_frame(unsigned card_index, uint16_t timecode,
                FrameAllocator::Frame video_frame, size_t video_offset, uint16_t video_format,
@@ -237,12 +228,7 @@ private:
        };
        CaptureCard cards[MAX_CARDS];  // protected by <bmusb_mutex>
 
-       // For each card, the last three frames (or fields), with 0 being the
-       // most recent one. Note that we only need the actual history if we have
-       // interlaced output (for deinterlacing), so if we detect progressive input,
-       // we immediately clear out all history and all entries will point to the same
-       // frame.
-       BufferedFrame buffered_frames[MAX_CARDS][FRAME_HISTORY_LENGTH];
+       InputState input_state;
 
        class OutputChannel {
        public:
index cfb9527f0dc97b6ad58324197fbac7e8afb70290..62e3640f509f2844df951df5db2b4e7476a8af1d 100644 (file)
--- a/theme.cpp
+++ b/theme.cpp
@@ -448,19 +448,13 @@ void LiveInputWrapper::connect_signal(int signal_num)
 
        signal_num = theme->map_signal(signal_num);
 
-       Mixer::BufferedFrame frame = global_mixer->get_buffered_frame(signal_num, 0);
+       BufferedFrame frame = theme->input_state->buffered_frames[signal_num][0];
        const PBOFrameAllocator::Userdata *userdata = (const PBOFrameAllocator::Userdata *)frame.frame->userdata;
 
        input->set_texture_num(0, userdata->tex_y[frame.field_number]);
        input->set_texture_num(1, userdata->tex_cbcr[frame.field_number]);
        input->set_width(userdata->last_width[frame.field_number]);
        input->set_height(userdata->last_height[frame.field_number]);
-
-       // Hold on to the refcount so that we don't release the input frame
-       // until we're done rendering from it.
-       if (theme->used_input_frames_collector != nullptr) {
-               theme->used_input_frames_collector->push_back(frame.frame);
-       }
 }
 
 Theme::Theme(const char *filename, ResourcePool *resource_pool, unsigned num_cards)
@@ -514,7 +508,7 @@ void Theme::register_class(const char *class_name, const luaL_Reg *funcs)
        assert(lua_gettop(L) == 0);
 }
 
-Theme::Chain Theme::get_chain(unsigned num, float t, unsigned width, unsigned height)
+Theme::Chain Theme::get_chain(unsigned num, float t, unsigned width, unsigned height, InputState input_state) 
 {
        Chain chain;
 
@@ -526,12 +520,10 @@ Theme::Chain Theme::get_chain(unsigned num, float t, unsigned width, unsigned he
        lua_pushnumber(L, width);
        lua_pushnumber(L, height);
 
-       this->used_input_frames_collector = &chain.input_frames;
        if (lua_pcall(L, 4, 2, 0) != 0) {
                fprintf(stderr, "error running function `get_chain': %s\n", lua_tostring(L, -1));
                exit(1);
        }
-       this->used_input_frames_collector = nullptr;
 
        chain.chain = (EffectChain *)luaL_checkudata(L, -2, "EffectChain");
        if (!lua_isfunction(L, -1)) {
@@ -543,9 +535,11 @@ Theme::Chain Theme::get_chain(unsigned num, float t, unsigned width, unsigned he
        lua_pop(L, 2);
        assert(lua_gettop(L) == 0);
 
-       chain.setup_chain = [this, funcref]{
+       chain.setup_chain = [this, funcref, input_state]{
                unique_lock<mutex> lock(m);
 
+               this->input_state = &input_state;
+
                // Set up state, including connecting signals.
                lua_rawgeti(L, LUA_REGISTRYINDEX, funcref->get());
                if (lua_pcall(L, 0, 0, 0) != 0) {
@@ -555,6 +549,14 @@ Theme::Chain Theme::get_chain(unsigned num, float t, unsigned width, unsigned he
                assert(lua_gettop(L) == 0);
        };
 
+       // TODO: Can we do better, e.g. by running setup_chain() and seeing what it references?
+       // Actually, setup_chain does maybe hold all the references we need now anyway?
+       for (unsigned card_index = 0; card_index < num_cards; ++card_index) {
+               for (unsigned frame_num = 0; frame_num < FRAME_HISTORY_LENGTH; ++frame_num) {
+                       chain.input_frames.push_back(input_state.buffered_frames[card_index][frame_num].frame);
+               }
+       }
+
        return chain;
 }
 
diff --git a/theme.h b/theme.h
index 2b3b4aba3a4e7297403b7493ad5a13ecddc1758a..223968a3c3b4b7201161b244af4b8be0dbd95c66 100644 (file)
--- a/theme.h
+++ b/theme.h
@@ -16,6 +16,7 @@
 #include <vector>
 
 #include "defs.h"
+#include "input_state.h"
 #include "ref_counted_frame.h"
 
 namespace movit {
@@ -47,7 +48,7 @@ public:
                std::vector<RefCountedFrame> input_frames;
        };
 
-       Chain get_chain(unsigned num, float t, unsigned width, unsigned height);
+       Chain get_chain(unsigned num, float t, unsigned width, unsigned height, InputState input_state);
 
        int get_num_channels() const { return num_channels; }
        int map_signal(int signal_num);
@@ -65,15 +66,13 @@ private:
        void register_class(const char *class_name, const luaL_Reg *funcs);
 
        std::mutex m;
-       lua_State *L;
+       lua_State *L;  // Protected by <m>.
+       const InputState *input_state;  // Protected by <m>. Only set temporarily, during chain setup.
        movit::ResourcePool *resource_pool;
        int num_channels;
        unsigned num_cards;
        std::set<int> signals_warned_about;
 
-       // All input frames needed for the current chain. Filled during call to get_chain(),
-       // as inputs get connected.
-       std::vector<RefCountedFrame> *used_input_frames_collector;
        friend class LiveInputWrapper;
 };