Extract J2K frame encoder classes for CPU and remote.
authorCarl Hetherington <cth@carlh.net>
Thu, 19 May 2022 23:11:35 +0000 (01:11 +0200)
committerCarl Hetherington <cth@carlh.net>
Mon, 23 May 2022 14:55:28 +0000 (16:55 +0200)
src/lib/cpu_j2k_frame_encoder.cc [new file with mode: 0644]
src/lib/cpu_j2k_frame_encoder.h [new file with mode: 0644]
src/lib/j2k_encoder.cc
src/lib/j2k_encoder.h
src/lib/j2k_frame_encoder.h [new file with mode: 0644]
src/lib/remote_j2k_frame_encoder.cc [new file with mode: 0644]
src/lib/remote_j2k_frame_encoder.h [new file with mode: 0644]
src/lib/wscript

diff --git a/src/lib/cpu_j2k_frame_encoder.cc b/src/lib/cpu_j2k_frame_encoder.cc
new file mode 100644 (file)
index 0000000..dcfbe9d
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+    Copyright (C) 2022 Carl Hetherington <cth@carlh.net>
+
+    This file is part of DCP-o-matic.
+
+    DCP-o-matic is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    DCP-o-matic is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with DCP-o-matic.  If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+
+#include "cpu_j2k_frame_encoder.h"
+#include "cross.h"
+#include "dcp_video.h"
+#include "dcpomatic_log.h"
+
+#include "i18n.h"
+
+
+using std::shared_ptr;
+using boost::optional;
+using dcp::ArrayData;
+
+
+optional<ArrayData>
+CPUJ2KFrameEncoder::encode (DCPVideo const& vf)
+{
+       optional<ArrayData> encoded;
+
+       try {
+               LOG_TIMING("start-local-encode thread=%1 frame=%2", thread_id(), vf.index());
+               encoded = vf.encode_locally();
+               LOG_TIMING("finish-local-encode thread=%1 frame=%2", thread_id(), vf.index());
+       } catch (std::exception& e) {
+               /* This is very bad, so don't cope with it, just pass it on */
+               LOG_ERROR(N_("Local encode failed (%1)"), e.what());
+               throw;
+       }
+
+       return encoded;
+}
+
+
+void
+CPUJ2KFrameEncoder::log_thread_start ()
+{
+        LOG_TIMING("start-encoder-thread thread=%1 server=localhost", thread_id());
+}
+
diff --git a/src/lib/cpu_j2k_frame_encoder.h b/src/lib/cpu_j2k_frame_encoder.h
new file mode 100644 (file)
index 0000000..5e866b0
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+    Copyright (C) 2022 Carl Hetherington <cth@carlh.net>
+
+    This file is part of DCP-o-matic.
+
+    DCP-o-matic is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    DCP-o-matic is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with DCP-o-matic.  If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+
+#ifndef DCPOMATIC_CPU_J2K_FRAME_ENCODER
+#define DCPOMATIC_CPU_J2K_FRAME_ENCODER
+
+
+#include "j2k_frame_encoder.h"
+
+
+class CPUJ2KFrameEncoder : public J2KFrameEncoder
+{
+public:
+       boost::optional<dcp::ArrayData> encode (DCPVideo const &) override;
+       void log_thread_start () override;
+};
+
+
+#endif
+
index 985708f054a762e4ab6bc468efdf7fd5b2d41bca..47d8b129559b173d7cf23acf8245d1f83221eac3 100644 (file)
@@ -26,6 +26,7 @@
 
 #include "compose.hpp"
 #include "config.h"
+#include "cpu_j2k_frame_encoder.h"
 #include "cross.h"
 #include "dcp_video.h"
 #include "dcpomatic_log.h"
@@ -36,6 +37,7 @@
 #include "log.h"
 #include "player.h"
 #include "player_video.h"
+#include "remote_j2k_frame_encoder.h"
 #include "util.h"
 #include "writer.h"
 #include <libcxml/cxml.h>
@@ -280,15 +282,12 @@ J2KEncoder::terminate_threads ()
 
 
 void
-J2KEncoder::encoder_thread (optional<EncodeServerDescription> server)
+J2KEncoder::encoder_thread (weak_ptr<J2KFrameEncoder> weak_worker)
 try
 {
-       start_of_thread ("J2KEncoder");
-
-       if (server) {
-               LOG_TIMING ("start-encoder-thread thread=%1 server=%2", thread_id (), server->host_name ());
-       } else {
-               LOG_TIMING ("start-encoder-thread thread=%1 server=localhost", thread_id ());
+       auto worker = weak_worker.lock();
+       if (!worker) {
+               return;
        }
 
        /* Number of seconds that we currently wait between attempts
@@ -320,45 +319,10 @@ try
 
                        lock.unlock ();
 
-                       shared_ptr<Data> encoded;
-
-                       /* We need to encode this input */
-                       if (server) {
-                               try {
-                                       encoded = make_shared<dcp::ArrayData>(vf.encode_remotely(server.get()));
-
-                                       if (remote_backoff > 0) {
-                                               LOG_GENERAL ("%1 was lost, but now she is found; removing backoff", server->host_name ());
-                                       }
-
-                                       /* This job succeeded, so remove any backoff */
-                                       remote_backoff = 0;
-
-                               } catch (std::exception& e) {
-                                       if (remote_backoff < 60) {
-                                               /* back off more */
-                                               remote_backoff += 10;
-                                       }
-                                       LOG_ERROR (
-                                               N_("Remote encode of %1 on %2 failed (%3); thread sleeping for %4s"),
-                                               vf.index(), server->host_name(), e.what(), remote_backoff
-                                               );
-                               }
-
-                       } else {
-                               try {
-                                       LOG_TIMING ("start-local-encode thread=%1 frame=%2", thread_id(), vf.index());
-                                       encoded = make_shared<dcp::ArrayData>(vf.encode_locally());
-                                       LOG_TIMING ("finish-local-encode thread=%1 frame=%2", thread_id(), vf.index());
-                               } catch (std::exception& e) {
-                                       /* This is very bad, so don't cope with it, just pass it on */
-                                       LOG_ERROR (N_("Local encode failed (%1)"), e.what ());
-                                       throw;
-                               }
-                       }
+                       auto encoded = worker->encode(vf);
 
                        if (encoded) {
-                               _writer->write (encoded, vf.index(), vf.eyes());
+                               _writer->write (make_shared<dcp::ArrayData>(*encoded), vf.index(), vf.eyes());
                                frame_done ();
                        } else {
                                lock.lock ();
@@ -401,11 +365,13 @@ J2KEncoder::servers_list_changed ()
 
        if (!Config::instance()->only_servers_encode ()) {
                for (int i = 0; i < Config::instance()->master_encoding_threads (); ++i) {
+                       auto worker = make_shared<CPUJ2KFrameEncoder>();
+                       _workers.push_back(worker);
 #ifdef DCPOMATIC_LINUX
-                       auto t = _threads->create_thread(boost::bind(&J2KEncoder::encoder_thread, this, optional<EncodeServerDescription>()));
+                       auto t = _threads->create_thread(boost::bind(&J2KEncoder::encoder_thread, this, worker));
                        pthread_setname_np (t->native_handle(), "encode-worker");
 #else
-                       _threads->create_thread(boost::bind(&J2KEncoder::encoder_thread, this, optional<EncodeServerDescription>()));
+                       _threads->create_thread(boost::bind(&J2KEncoder::encoder_thread, this, worker));
 #endif
                }
        }
@@ -417,7 +383,9 @@ J2KEncoder::servers_list_changed ()
 
                LOG_GENERAL (N_("Adding %1 worker threads for remote %2"), i.threads(), i.host_name ());
                for (int j = 0; j < i.threads(); ++j) {
-                       _threads->create_thread(boost::bind(&J2KEncoder::encoder_thread, this, i));
+                       auto worker = make_shared<RemoteJ2KFrameEncoder>(i);
+                       _workers.push_back(worker);
+                       _threads->create_thread(boost::bind(&J2KEncoder::encoder_thread, this, worker));
                }
        }
 
index ea0a2bef89bfbe873a83cbad11be48a1a0788985..5a7db6441f1b8697bde95907551cd703d1e86b8a 100644 (file)
 #include <stdint.h>
 
 
-class Film;
-class EncodeServerDescription;
 class DCPVideo;
-class Writer;
+class EncodeServerDescription;
+class Film;
+class J2KFrameEncoder;
 class Job;
 class PlayerVideo;
+class Writer;
 
 
 /** @class J2KEncoder
@@ -84,7 +85,7 @@ private:
 
        void frame_done ();
 
-       void encoder_thread (boost::optional<EncodeServerDescription>);
+       void encoder_thread (std::weak_ptr<J2KFrameEncoder> worker);
        void terminate_threads ();
 
        /** Film that we are encoding */
@@ -97,6 +98,7 @@ private:
 
        mutable boost::mutex _queue_mutex;
        std::list<DCPVideo> _queue;
+       std::list<std::shared_ptr<J2KFrameEncoder>> _workers;
        /** condition to manage thread wakeups when we have nothing to do */
        boost::condition _empty_condition;
        /** condition to manage thread wakeups when we have too much to do */
diff --git a/src/lib/j2k_frame_encoder.h b/src/lib/j2k_frame_encoder.h
new file mode 100644 (file)
index 0000000..33f9876
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+    Copyright (C) 2022 Carl Hetherington <cth@carlh.net>
+
+    This file is part of DCP-o-matic.
+
+    DCP-o-matic is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    DCP-o-matic is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with DCP-o-matic.  If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+
+#ifndef DCPOMATIC_J2K_FRAME_ENCODER
+#define DCPOMATIC_J2K_FRAME_ENCODER
+
+
+#include <dcp/array_data.h>
+#include <boost/optional.hpp>
+#include <memory>
+
+
+class DCPVideo;
+
+
+class J2KFrameEncoder
+{
+public:
+       virtual ~J2KFrameEncoder() {}
+
+       virtual boost::optional<dcp::ArrayData> encode (DCPVideo const &) = 0;
+       virtual void log_thread_start () = 0;
+};
+
+
+#endif
+
diff --git a/src/lib/remote_j2k_frame_encoder.cc b/src/lib/remote_j2k_frame_encoder.cc
new file mode 100644 (file)
index 0000000..3917cc0
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+    Copyright (C) 2022 Carl Hetherington <cth@carlh.net>
+
+    This file is part of DCP-o-matic.
+
+    DCP-o-matic is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    DCP-o-matic is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with DCP-o-matic.  If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+
+#include "cross.h"
+#include "dcp_video.h"
+#include "dcpomatic_log.h"
+#include "remote_j2k_frame_encoder.h"
+
+#include "i18n.h"
+
+
+using std::make_shared;
+using std::shared_ptr;
+using boost::optional;
+using dcp::Data;
+
+
+optional<dcp::ArrayData>
+RemoteJ2KFrameEncoder::encode(DCPVideo const& vf)
+{
+       optional<dcp::ArrayData> encoded;
+
+       try {
+               encoded = vf.encode_remotely(_server);
+
+               if (_remote_backoff > 0) {
+                       LOG_GENERAL ("%1 was lost, but now she is found; removing backoff", _server.host_name());
+               }
+
+               /* This job succeeded, so remove any backoff */
+               _remote_backoff = 0;
+
+       } catch (std::exception& e) {
+               if (_remote_backoff < 60) {
+                       /* back off more */
+                       _remote_backoff += 10;
+               }
+               LOG_ERROR (
+                       N_("Remote encode of %1 on %2 failed (%3); thread sleeping for %4s"),
+                       vf.index(), _server.host_name(), e.what(), _remote_backoff
+                       );
+       }
+
+       return encoded;
+}
+
+
+void
+RemoteJ2KFrameEncoder::log_thread_start ()
+{
+       LOG_TIMING("start-encoder-thread thread=%1 server=%2", thread_id(), _server.host_name());
+}
+
diff --git a/src/lib/remote_j2k_frame_encoder.h b/src/lib/remote_j2k_frame_encoder.h
new file mode 100644 (file)
index 0000000..e532782
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+    Copyright (C) 2022 Carl Hetherington <cth@carlh.net>
+
+    This file is part of DCP-o-matic.
+
+    DCP-o-matic is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    DCP-o-matic is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with DCP-o-matic.  If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+
+#ifndef DCPOMATIC_REMOTE_J2K_FRAME_ENCODER
+#define DCPOMATIC_REMOTE_J2K_FRAME_ENCODER
+
+
+#include "j2k_frame_encoder.h"
+
+
+class RemoteJ2KFrameEncoder : public J2KFrameEncoder
+{
+public:
+       RemoteJ2KFrameEncoder(EncodeServerDescription s)
+               : _server(s)
+       {}
+
+       boost::optional<dcp::ArrayData> encode (DCPVideo const &) override;
+       void log_thread_start () override;
+
+private:
+       EncodeServerDescription _server;
+       int _remote_backoff = 0;
+};
+
+
+#endif
+
index 7400c5bf11ab2863fb78b4f4c4ab3afc01dee60a..1e8fd6f251d2a7c8a5d9e29f22354450cba1d885 100644 (file)
@@ -57,6 +57,7 @@ sources = """
           content_factory.cc
           combine_dcp_job.cc
           copy_dcp_details_to_film.cc
+          cpu_j2k_frame_encoder.cc
           create_cli.cc
           cross_common.cc
           crypto.cc
@@ -151,6 +152,7 @@ sources = """
           ratio.cc
           raw_image_proxy.cc
           reel_writer.cc
+          remote_j2k_frame_encoder.cc
           render_text.cc
           resampler.cc
           rgba.cc