Add configuration option to set writer's maximum frames in memory.
authorCarl Hetherington <cth@carlh.net>
Thu, 5 Oct 2017 00:34:07 +0000 (01:34 +0100)
committerCarl Hetherington <cth@carlh.net>
Thu, 5 Oct 2017 00:34:07 +0000 (01:34 +0100)
ChangeLog
src/lib/config.cc
src/lib/config.h
src/lib/writer.cc
src/wx/full_config_dialog.cc

index 6fd1ba9..6438d59 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,8 @@
+2017-10-05  Carl Hetherington  <cth@carlh.net>
+
+       * Add config option to control writer's
+       maximum_frames_in_memory.
+
 2017-10-04  Carl Hetherington  <cth@carlh.net>
 
        * Updated da_DK translation from Anders Uhl Pedersen.
index 4f481ef..8dabcb7 100644 (file)
@@ -129,6 +129,17 @@ Config::set_defaults ()
        _sound = false;
        _sound_output = optional<string> ();
 
+       /* I think the scaling factor here should be the ratio of the longest frame
+          encode time to the shortest; if the thread count is T, longest time is L
+          and the shortest time S we could encode L/S frames per thread whilst waiting
+          for the L frame to encode so we might have to store LT/S frames.
+
+          However we don't want to use too much memory, so keep it a bit lower than we'd
+          perhaps like.  A J2K frame is typically about 1Mb so 3 here will mean we could
+          use about 240Mb with 72 encoding threads.
+       */
+       _frames_in_memory_multiplier = 3;
+
        _allowed_dcp_frame_rates.clear ();
        _allowed_dcp_frame_rates.push_back (24);
        _allowed_dcp_frame_rates.push_back (25);
@@ -355,6 +366,7 @@ try
                _cover_sheet = f.optional_string_child("CoverSheet").get();
        }
        _last_player_load_directory = f.optional_string_child("LastPlayerLoadDirectory");
+       _frames_in_memory_multiplier = f.optional_number_child<int>("FramesInMemoryMultiplier").get_value_or(3);
 
        /* Replace any cinemas from config.xml with those from the configured file */
        if (boost::filesystem::exists (_cinemas_file)) {
@@ -635,6 +647,10 @@ Config::write_config () const
        if (_last_player_load_directory) {
                root->add_child("LastPlayerLoadDirectory")->add_child_text(_last_player_load_directory->string());
        }
+       /* [XML] FramesInMemoryMultiplier value to multiply the encoding threads count by to get the maximum number of
+          frames to be held in memory at once.
+       */
+       root->add_child("FramesInMemoryMultiplier")->add_child_text(raw_convert<string>(_frames_in_memory_multiplier));
 
        try {
                doc.write_to_file_formatted(config_file().string());
index 2d45f14..afa362a 100644 (file)
@@ -345,6 +345,10 @@ public:
                return _last_player_load_directory;
        }
 
+       int frames_in_memory_multiplier () const {
+               return _frames_in_memory_multiplier;
+       }
+
        void set_master_encoding_threads (int n) {
                maybe_set (_master_encoding_threads, n);
        }
@@ -604,6 +608,10 @@ public:
                maybe_set (_dcp_asset_filename_format, n);
        }
 
+       void set_frames_in_memory_multiplier (int m) {
+               maybe_set (_frames_in_memory_multiplier, m);
+       }
+
        void clear_history () {
                _history.clear ();
                changed ();
@@ -771,6 +779,7 @@ private:
        boost::optional<std::string> _sound_output;
        std::string _cover_sheet;
        boost::optional<boost::filesystem::path> _last_player_load_directory;
+       int _frames_in_memory_multiplier;
 
        /** Singleton instance, or 0 */
        static Config* _instance;
index b5123ad..3f0c687 100644 (file)
@@ -676,16 +676,7 @@ operator== (QueueItem const & a, QueueItem const & b)
 void
 Writer::set_encoder_threads (int threads)
 {
-       /* I think the scaling factor here should be the ratio of the longest frame
-          encode time to the shortest; if the thread count is T, longest time is L
-          and the shortest time S we could encode L/S frames per thread whilst waiting
-          for the L frame to encode so we might have to store LT/S frames.
-
-          However we don't want to use too much memory, so keep it a bit lower than we'd
-          perhaps like.  A J2K frame is typically about 1Mb so 3 here will mean we could
-          use about 240Mb with 72 encoding threads.
-       */
-       _maximum_frames_in_memory = lrint (threads * 3);
+       _maximum_frames_in_memory = lrint (threads * Config::instance()->frames_in_memory_multiplier());
 }
 
 void
index b5f9a48..35f6f1f 100644 (file)
@@ -966,6 +966,14 @@ private:
                table->AddSpacer (0);
 
                {
+                       add_label_to_sizer (table, _panel, _("Maximum number of frames to store per thread"), true);
+                       wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL);
+                       _frames_in_memory_multiplier = new wxSpinCtrl (_panel);
+                       s->Add (_frames_in_memory_multiplier, 1);
+                       table->Add (s, 1);
+               }
+
+               {
                        add_top_aligned_label_to_sizer (table, _panel, _("DCP metadata filename format"));
                        dcp::NameFormat::Map titles;
                        titles['t'] = "type (cpl/pkl)";
@@ -1026,6 +1034,7 @@ private:
                _maximum_j2k_bandwidth->Bind (wxEVT_SPINCTRL, boost::bind (&AdvancedPage::maximum_j2k_bandwidth_changed, this));
                _allow_any_dcp_frame_rate->Bind (wxEVT_CHECKBOX, boost::bind (&AdvancedPage::allow_any_dcp_frame_rate_changed, this));
                _only_servers_encode->Bind (wxEVT_CHECKBOX, boost::bind (&AdvancedPage::only_servers_encode_changed, this));
+               _frames_in_memory_multiplier->Bind (wxEVT_SPINCTRL, boost::bind(&AdvancedPage::frames_in_memory_multiplier_changed, this));
                _dcp_metadata_filename_format->Changed.connect (boost::bind (&AdvancedPage::dcp_metadata_filename_format_changed, this));
                _dcp_asset_filename_format->Changed.connect (boost::bind (&AdvancedPage::dcp_asset_filename_format_changed, this));
                _log_general->Bind (wxEVT_CHECKBOX, boost::bind (&AdvancedPage::log_changed, this));
@@ -1054,6 +1063,7 @@ private:
                checked_set (_log_debug_decode, config->log_types() & LogEntry::TYPE_DEBUG_DECODE);
                checked_set (_log_debug_encode, config->log_types() & LogEntry::TYPE_DEBUG_ENCODE);
                checked_set (_log_debug_email, config->log_types() & LogEntry::TYPE_DEBUG_EMAIL);
+               checked_set (_frames_in_memory_multiplier, config->frames_in_memory_multiplier());
 #ifdef DCPOMATIC_WINDOWS
                checked_set (_win32_console, config->win32_console());
 #endif
@@ -1064,6 +1074,11 @@ private:
                Config::instance()->set_maximum_j2k_bandwidth (_maximum_j2k_bandwidth->GetValue() * 1000000);
        }
 
+       void frames_in_memory_multiplier_changed ()
+       {
+               Config::instance()->set_frames_in_memory_multiplier (_frames_in_memory_multiplier->GetValue());
+       }
+
        void allow_any_dcp_frame_rate_changed ()
        {
                Config::instance()->set_allow_any_dcp_frame_rate (_allow_any_dcp_frame_rate->GetValue ());
@@ -1119,6 +1134,7 @@ private:
 #endif
 
        wxSpinCtrl* _maximum_j2k_bandwidth;
+       wxSpinCtrl* _frames_in_memory_multiplier;
        wxCheckBox* _allow_any_dcp_frame_rate;
        wxCheckBox* _only_servers_encode;
        NameFormatEditor* _dcp_metadata_filename_format;