summaryrefslogtreecommitdiff
path: root/src/lib
diff options
context:
space:
mode:
authorCarl Hetherington <cth@carlh.net>2020-08-13 14:55:20 +0200
committerCarl Hetherington <cth@carlh.net>2020-09-13 20:23:29 +0200
commit50e85cf64504b7fc38b4129aa750c2def28b95fd (patch)
tree12d30de6149bc7fa39ab388397da128a7d426a44 /src/lib
parentdbb5577ff761cfd25f154fc54c2dc7e111a31c77 (diff)
Rearrange encoding so that the different methods / backends are not all crammed into DCPVideo.
Diffstat (limited to 'src/lib')
-rw-r--r--src/lib/dcp_video.cc96
-rw-r--r--src/lib/dcp_video.h21
-rw-r--r--src/lib/encode_server.cc10
-rw-r--r--src/lib/encode_server.h3
-rw-r--r--src/lib/j2k_encoder.cc82
-rw-r--r--src/lib/j2k_encoder.h11
-rw-r--r--src/lib/j2k_encoder_backend.h19
-rw-r--r--src/lib/j2k_encoder_cpu_backend.cc56
-rw-r--r--src/lib/j2k_encoder_cpu_backend.h14
-rw-r--r--src/lib/j2k_encoder_remote_backend.cc108
-rw-r--r--src/lib/j2k_encoder_remote_backend.h16
-rw-r--r--src/lib/wscript4
12 files changed, 266 insertions, 174 deletions
diff --git a/src/lib/dcp_video.cc b/src/lib/dcp_video.cc
index 440571b76..161f74c57 100644
--- a/src/lib/dcp_video.cc
+++ b/src/lib/dcp_video.cc
@@ -32,7 +32,6 @@
#include "config.h"
#include "exceptions.h"
#include "encode_server_description.h"
-#include "dcpomatic_socket.h"
#include "image.h"
#include "log.h"
#include "dcpomatic_log.h"
@@ -48,7 +47,6 @@
DCPOMATIC_DISABLE_WARNINGS
#include <libxml++/libxml++.h>
DCPOMATIC_ENABLE_WARNINGS
-#include <boost/asio.hpp>
#include <boost/thread.hpp>
#include <stdint.h>
#include <iomanip>
@@ -117,95 +115,6 @@ DCPVideo::convert_to_xyz (shared_ptr<const PlayerVideo> frame, dcp::NoteHandler
return xyz;
}
-/** J2K-encode this frame on the local host.
- * @return Encoded data.
- */
-Data
-DCPVideo::encode_locally ()
-{
- string const comment = Config::instance()->dcp_j2k_comment();
-
- Data enc = dcp::compress_j2k (
- convert_to_xyz (_frame, boost::bind(&Log::dcp_log, dcpomatic_log.get(), _1, _2)),
- _j2k_bandwidth,
- _frames_per_second,
- _frame->eyes() == EYES_LEFT || _frame->eyes() == EYES_RIGHT,
- _resolution == RESOLUTION_4K,
- comment.empty() ? "libdcp" : comment
- );
-
- switch (_frame->eyes()) {
- case EYES_BOTH:
- LOG_DEBUG_ENCODE (N_("Finished locally-encoded frame %1 for mono"), _index);
- break;
- case EYES_LEFT:
- LOG_DEBUG_ENCODE (N_("Finished locally-encoded frame %1 for L"), _index);
- break;
- case EYES_RIGHT:
- LOG_DEBUG_ENCODE (N_("Finished locally-encoded frame %1 for R"), _index);
- break;
- default:
- break;
- }
-
- return enc;
-}
-
-/** Send this frame to a remote server for J2K encoding, then read the result.
- * @param serv Server to send to.
- * @param timeout timeout in seconds.
- * @return Encoded data.
- */
-Data
-DCPVideo::encode_remotely (EncodeServerDescription serv, int timeout)
-{
- boost::asio::io_service io_service;
- boost::asio::ip::tcp::resolver resolver (io_service);
- boost::asio::ip::tcp::resolver::query query (serv.host_name(), raw_convert<string> (ENCODE_FRAME_PORT));
- boost::asio::ip::tcp::resolver::iterator endpoint_iterator = resolver.resolve (query);
-
- shared_ptr<Socket> socket (new Socket (timeout));
-
- socket->connect (*endpoint_iterator);
-
- /* Collect all XML metadata */
- xmlpp::Document doc;
- xmlpp::Element* root = doc.create_root_node ("EncodingRequest");
- root->add_child("Version")->add_child_text (raw_convert<string> (SERVER_LINK_VERSION));
- add_metadata (root);
-
- LOG_DEBUG_ENCODE (N_("Sending frame %1 to remote"), _index);
-
- {
- Socket::WriteDigestScope ds (socket);
-
- /* Send XML metadata */
- string xml = doc.write_to_string ("UTF-8");
- socket->write (xml.length() + 1);
- socket->write ((uint8_t *) xml.c_str(), xml.length() + 1);
-
- /* Send binary data */
- LOG_TIMING("start-remote-send thread=%1", thread_id ());
- _frame->write_to_socket (socket);
- }
-
- /* Read the response (JPEG2000-encoded data); this blocks until the data
- is ready and sent back.
- */
- Socket::ReadDigestScope ds (socket);
- LOG_TIMING("start-remote-encode thread=%1", thread_id ());
- Data e (socket->read_uint32 ());
- LOG_TIMING("start-remote-receive thread=%1", thread_id ());
- socket->read (e.data().get(), e.size());
- LOG_TIMING("finish-remote-receive thread=%1", thread_id ());
- if (!ds.check()) {
- throw NetworkError ("Checksums do not match");
- }
-
- LOG_DEBUG_ENCODE (N_("Finished remotely-encoded frame %1"), _index);
-
- return e;
-}
void
DCPVideo::add_metadata (xmlpp::Element* el) const
@@ -217,11 +126,6 @@ DCPVideo::add_metadata (xmlpp::Element* el) const
_frame->add_metadata (el);
}
-Eyes
-DCPVideo::eyes () const
-{
- return _frame->eyes ();
-}
/** @return true if this DCPVideo is definitely the same as another;
* (apart from the frame index), false if it is probably not.
diff --git a/src/lib/dcp_video.h b/src/lib/dcp_video.h
index 81ddc4470..49a858733 100644
--- a/src/lib/dcp_video.h
+++ b/src/lib/dcp_video.h
@@ -45,23 +45,32 @@ public:
DCPVideo (boost::shared_ptr<const PlayerVideo>, int, int, int, Resolution);
DCPVideo (boost::shared_ptr<const PlayerVideo>, cxml::ConstNodePtr);
- dcp::Data encode_locally ();
- dcp::Data encode_remotely (EncodeServerDescription, int timeout = 30);
+ boost::shared_ptr<const PlayerVideo> frame () const {
+ return _frame;
+ }
int index () const {
return _index;
}
- Eyes eyes () const;
+ int frames_per_second () const {
+ return _frames_per_second;
+ }
+
+ int j2k_bandwidth () const {
+ return _j2k_bandwidth;
+ }
+
+ Resolution resolution () const {
+ return _resolution;
+ }
bool same (boost::shared_ptr<const DCPVideo> other) const;
+ void add_metadata (xmlpp::Element *) const;
static boost::shared_ptr<dcp::OpenJPEGImage> convert_to_xyz (boost::shared_ptr<const PlayerVideo> frame, dcp::NoteHandler note);
private:
-
- void add_metadata (xmlpp::Element *) const;
-
boost::shared_ptr<const PlayerVideo> _frame;
int _index; ///< frame index within the DCP's intrinsic duration
int _frames_per_second; ///< Frames per second that we will use for the DCP
diff --git a/src/lib/encode_server.cc b/src/lib/encode_server.cc
index f4224798b..85f3ca7b0 100644
--- a/src/lib/encode_server.cc
+++ b/src/lib/encode_server.cc
@@ -141,11 +141,11 @@ EncodeServer::process (shared_ptr<Socket> socket, struct timeval& after_read, st
throw NetworkError ("Checksums do not match");
}
- DCPVideo dcp_video_frame (pvf, xml);
+ shared_ptr<DCPVideo> frame(new DCPVideo(pvf, xml));
gettimeofday (&after_read, 0);
- Data encoded = dcp_video_frame.encode_locally ();
+ Data encoded = *_cpu_encoder.encode (frame);
gettimeofday (&after_encode, 0);
@@ -154,12 +154,12 @@ EncodeServer::process (shared_ptr<Socket> socket, struct timeval& after_read, st
socket->write (encoded.size());
socket->write (encoded.data().get(), encoded.size());
} catch (std::exception& e) {
- cerr << "Send failed; frame " << dcp_video_frame.index() << "\n";
- LOG_ERROR ("Send failed; frame %1", dcp_video_frame.index());
+ cerr << "Send failed; frame " << frame->index() << "\n";
+ LOG_ERROR ("Send failed; frame %1", frame->index());
throw;
}
- return dcp_video_frame.index ();
+ return frame->index ();
}
void
diff --git a/src/lib/encode_server.h b/src/lib/encode_server.h
index a43cea7ef..af1ead2bb 100644
--- a/src/lib/encode_server.h
+++ b/src/lib/encode_server.h
@@ -27,6 +27,7 @@
#include "server.h"
#include "exception_store.h"
+#include "j2k_encoder_cpu_backend.h"
#include <boost/thread.hpp>
#include <boost/asio.hpp>
#include <boost/thread/condition.hpp>
@@ -61,6 +62,8 @@ private:
bool _verbose;
int _num_threads;
+ J2KEncoderCPUBackend _cpu_encoder;
+
struct Broadcast {
Broadcast ()
diff --git a/src/lib/j2k_encoder.cc b/src/lib/j2k_encoder.cc
index 64cd38147..ef38aaa55 100644
--- a/src/lib/j2k_encoder.cc
+++ b/src/lib/j2k_encoder.cc
@@ -1,5 +1,5 @@
/*
- Copyright (C) 2012-2019 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2012-2020 Carl Hetherington <cth@carlh.net>
This file is part of DCP-o-matic.
@@ -23,6 +23,9 @@
*/
#include "j2k_encoder.h"
+#include "j2k_encoder_backend.h"
+#include "j2k_encoder_cpu_backend.h"
+#include "j2k_encoder_remote_backend.h"
#include "util.h"
#include "film.h"
#include "log.h"
@@ -57,6 +60,7 @@ using namespace dcpomatic;
J2KEncoder::J2KEncoder (shared_ptr<const Film> film, shared_ptr<Writer> writer)
: _film (film)
, _history (200)
+ , _cpu_backend (new J2KEncoderCPUBackend())
, _writer (writer)
{
servers_list_changed ();
@@ -123,13 +127,13 @@ J2KEncoder::end ()
So just mop up anything left in the queue here.
*/
- for (list<shared_ptr<DCPVideo> >::iterator i = _queue.begin(); i != _queue.end(); ++i) {
- LOG_GENERAL (N_("Encode left-over frame %1"), (*i)->index ());
+ BOOST_FOREACH (shared_ptr<DCPVideo> i, _queue) {
+ LOG_GENERAL (N_("Encode left-over frame %1"), i->index());
try {
_writer->write (
- (*i)->encode_locally(),
- (*i)->index(),
- (*i)->eyes()
+ *_cpu_backend->encode(i),
+ i->index(),
+ i->frame()->eyes()
);
frame_done ();
} catch (std::exception& e) {
@@ -258,20 +262,10 @@ J2KEncoder::terminate_threads ()
}
void
-J2KEncoder::encoder_thread (optional<EncodeServerDescription> server)
+J2KEncoder::encoder_thread (shared_ptr<J2KEncoderBackend> backend)
try
{
- 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 ());
- }
-
- /* Number of seconds that we currently wait between attempts
- to connect to the server; not relevant for localhost
- encodings.
- */
- int remote_backoff = 0;
+ LOG_TIMING ("start-encoder-thread thread=%1", thread_id());
while (true) {
@@ -291,50 +285,15 @@ try
{
boost::this_thread::disable_interruption dis;
- LOG_TIMING ("encoder-pop thread=%1 frame=%2 eyes=%3", thread_id(), vf->index(), (int) vf->eyes ());
+ LOG_TIMING ("encoder-pop thread=%1 frame=%2 eyes=%3", thread_id(), vf->index(), (int) vf->frame()->eyes());
_queue.pop_front ();
lock.unlock ();
- optional<Data> encoded;
-
- /* We need to encode this input */
- if (server) {
- try {
- encoded = 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 = 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;
- }
- }
+ optional<Data> encoded = backend->encode (vf);
if (encoded) {
- _writer->write (encoded.get(), vf->index (), vf->eyes ());
+ _writer->write (encoded.get(), vf->index (), vf->frame()->eyes());
frame_done ();
} else {
lock.lock ();
@@ -344,10 +303,6 @@ try
}
}
- if (remote_backoff > 0) {
- boost::this_thread::sleep (boost::posix_time::seconds (remote_backoff));
- }
-
/* The queue might not be full any more, so notify anything that is waiting on that */
lock.lock ();
_full_condition.notify_all ();
@@ -375,10 +330,10 @@ J2KEncoder::servers_list_changed ()
if (!Config::instance()->only_servers_encode ()) {
for (int i = 0; i < Config::instance()->master_encoding_threads (); ++i) {
#ifdef DCPOMATIC_LINUX
- boost::thread* t = _threads->create_thread(boost::bind(&J2KEncoder::encoder_thread, this, optional<EncodeServerDescription>()));
+ boost::thread* t = _threads->create_thread(boost::bind(&J2KEncoder::encoder_thread, this, _cpu_backend));
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, _cpu_backend));
#endif
}
}
@@ -389,8 +344,9 @@ J2KEncoder::servers_list_changed ()
}
LOG_GENERAL (N_("Adding %1 worker threads for remote %2"), i.threads(), i.host_name ());
+ shared_ptr<J2KEncoderRemoteBackend> backend (new J2KEncoderRemoteBackend(i));
for (int j = 0; j < i.threads(); ++j) {
- _threads->create_thread(boost::bind(&J2KEncoder::encoder_thread, this, i));
+ _threads->create_thread(boost::bind(&J2KEncoder::encoder_thread, this, backend));
}
}
diff --git a/src/lib/j2k_encoder.h b/src/lib/j2k_encoder.h
index d56fc1aec..df23a5bae 100644
--- a/src/lib/j2k_encoder.h
+++ b/src/lib/j2k_encoder.h
@@ -1,5 +1,5 @@
/*
- Copyright (C) 2012-2016 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2012-2020 Carl Hetherington <cth@carlh.net>
This file is part of DCP-o-matic.
@@ -45,6 +45,10 @@ class DCPVideo;
class Writer;
class Job;
class PlayerVideo;
+class J2KEncoderBackend;
+class J2KEncoderCPUBackend;
+class J2KEncoderRemoteBackend;
+
/** @class J2KEncoder
* @brief Class to manage encoding to J2K.
@@ -79,16 +83,17 @@ private:
void frame_done ();
- void encoder_thread (boost::optional<EncodeServerDescription>);
+ void encoder_thread (boost::shared_ptr<J2KEncoderBackend> backend);
void terminate_threads ();
- /** Film that we are encoding */
boost::shared_ptr<const Film> _film;
EventHistory _history;
boost::shared_ptr<boost::thread_group> _threads;
+ boost::shared_ptr<J2KEncoderCPUBackend> _cpu_backend;
+
mutable boost::mutex _queue_mutex;
std::list<boost::shared_ptr<DCPVideo> > _queue;
/** condition to manage thread wakeups when we have nothing to do */
diff --git a/src/lib/j2k_encoder_backend.h b/src/lib/j2k_encoder_backend.h
new file mode 100644
index 000000000..7688e5f15
--- /dev/null
+++ b/src/lib/j2k_encoder_backend.h
@@ -0,0 +1,19 @@
+#ifndef DCPOMATIC_J2K_ENCODER_BACKEND_H
+#define DCPOMATIC_J2K_ENCODER_BACKEND_H
+
+#include <dcp/data.h>
+#include <boost/noncopyable.hpp>
+#include <boost/optional.hpp>
+#include <boost/shared_ptr.hpp>
+
+
+class DCPVideo;
+
+
+class J2KEncoderBackend : public boost::noncopyable
+{
+public:
+ virtual boost::optional<dcp::Data> encode (boost::shared_ptr<DCPVideo> video) = 0;
+};
+
+#endif
diff --git a/src/lib/j2k_encoder_cpu_backend.cc b/src/lib/j2k_encoder_cpu_backend.cc
new file mode 100644
index 000000000..732913c06
--- /dev/null
+++ b/src/lib/j2k_encoder_cpu_backend.cc
@@ -0,0 +1,56 @@
+#include "config.h"
+#include "cross.h"
+#include "dcp_video.h"
+#include "dcpomatic_log.h"
+#include "j2k_encoder_cpu_backend.h"
+#include "player_video.h"
+#include <dcp/j2k.h>
+
+#include "i18n.h"
+
+
+using std::string;
+using boost::optional;
+using boost::shared_ptr;
+using dcp::Data;
+
+
+optional<Data>
+J2KEncoderCPUBackend::encode (shared_ptr<DCPVideo> video)
+{
+ try {
+ LOG_TIMING ("start-local-encode thread=%1 frame=%2", thread_id(), video->index());
+ string const comment = Config::instance()->dcp_j2k_comment();
+
+ Data enc = dcp::compress_j2k (
+ DCPVideo::convert_to_xyz (video->frame(), boost::bind(&Log::dcp_log, dcpomatic_log.get(), _1, _2)),
+ video->j2k_bandwidth(),
+ video->frames_per_second(),
+ video->frame()->eyes() == EYES_LEFT || video->frame()->eyes() == EYES_RIGHT,
+ video->resolution() == RESOLUTION_4K,
+ comment.empty() ? "libdcp" : comment
+ );
+
+ switch (video->frame()->eyes()) {
+ case EYES_BOTH:
+ LOG_DEBUG_ENCODE (N_("Finished locally-encoded frame %1 for mono"), video->index());
+ break;
+ case EYES_LEFT:
+ LOG_DEBUG_ENCODE (N_("Finished locally-encoded frame %1 for L"), video->index());
+ break;
+ case EYES_RIGHT:
+ LOG_DEBUG_ENCODE (N_("Finished locally-encoded frame %1 for R"), video->index());
+ break;
+ default:
+ break;
+ }
+
+ LOG_TIMING ("finish-local-encode thread=%1 frame=%2", thread_id(), video->index());
+ return enc;
+ } 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;
+ }
+}
+
diff --git a/src/lib/j2k_encoder_cpu_backend.h b/src/lib/j2k_encoder_cpu_backend.h
new file mode 100644
index 000000000..75d7c97a7
--- /dev/null
+++ b/src/lib/j2k_encoder_cpu_backend.h
@@ -0,0 +1,14 @@
+#ifndef DCPOMATIC_J2K_ENCODER_CPU_BACKEND_H
+#define DCPOMATIC_J2K_ENCODER_CPU_BACKEND_H
+
+
+#include "j2k_encoder_backend.h"
+
+
+class J2KEncoderCPUBackend : public J2KEncoderBackend
+{
+public:
+ boost::optional<dcp::Data> encode (boost::shared_ptr<DCPVideo> video);
+};
+
+#endif
diff --git a/src/lib/j2k_encoder_remote_backend.cc b/src/lib/j2k_encoder_remote_backend.cc
new file mode 100644
index 000000000..831134718
--- /dev/null
+++ b/src/lib/j2k_encoder_remote_backend.cc
@@ -0,0 +1,108 @@
+#include "config.h"
+#include "cross.h"
+#include "dcp_video.h"
+#include "dcpomatic_log.h"
+#include "dcpomatic_socket.h"
+#include "encode_server_description.h"
+#include "j2k_encoder_remote_backend.h"
+#include "player_video.h"
+#include "warnings.h"
+#include <dcp/raw_convert.h>
+DCPOMATIC_DISABLE_WARNINGS
+#include <libxml++/libxml++.h>
+DCPOMATIC_ENABLE_WARNINGS
+#include <boost/asio.hpp>
+#include <boost/thread.hpp>
+
+#include "i18n.h"
+
+
+using std::string;
+using boost::optional;
+using boost::shared_ptr;
+using dcp::Data;
+using dcp::raw_convert;
+
+
+J2KEncoderRemoteBackend::J2KEncoderRemoteBackend (EncodeServerDescription server)
+ : _server (server)
+ , _backoff (0)
+{
+
+}
+
+
+optional<Data>
+J2KEncoderRemoteBackend::encode (shared_ptr<DCPVideo> video)
+{
+ int const timeout = 30;
+
+ try {
+ boost::asio::io_service io_service;
+ boost::asio::ip::tcp::resolver resolver (io_service);
+ boost::asio::ip::tcp::resolver::query query (_server.host_name(), raw_convert<string>(ENCODE_FRAME_PORT));
+ boost::asio::ip::tcp::resolver::iterator endpoint_iterator = resolver.resolve (query);
+
+ shared_ptr<Socket> socket (new Socket(timeout));
+
+ socket->connect (*endpoint_iterator);
+
+ /* Collect all XML metadata */
+ xmlpp::Document doc;
+ xmlpp::Element* root = doc.create_root_node ("EncodingRequest");
+ root->add_child("Version")->add_child_text(raw_convert<string> (SERVER_LINK_VERSION));
+ video->add_metadata (root);
+
+ LOG_DEBUG_ENCODE (N_("Sending frame %1 to remote"), video->index());
+
+ {
+ Socket::WriteDigestScope ds (socket);
+
+ /* Send XML metadata */
+ string xml = doc.write_to_string ("UTF-8");
+ socket->write (xml.length() + 1);
+ socket->write ((uint8_t *) xml.c_str(), xml.length() + 1);
+
+ /* Send binary data */
+ LOG_TIMING("start-remote-send thread=%1", thread_id());
+ video->frame()->write_to_socket(socket);
+ }
+
+ /* Read the response (JPEG2000-encoded data); this blocks until the data
+ is ready and sent back.
+ */
+ Socket::ReadDigestScope ds (socket);
+ LOG_TIMING("start-remote-encode thread=%1", thread_id());
+ Data e (socket->read_uint32 ());
+ LOG_TIMING("start-remote-receive thread=%1", thread_id());
+ socket->read (e.data().get(), e.size());
+ LOG_TIMING("finish-remote-receive thread=%1", thread_id());
+ if (!ds.check()) {
+ throw NetworkError ("Checksums do not match");
+ }
+
+ LOG_DEBUG_ENCODE (N_("Finished remotely-encoded frame %1"), video->index());
+
+ if (_backoff > 0) {
+ LOG_GENERAL ("%1 was lost, but now she is found; removing backoff", _server.host_name());
+ }
+
+ /* This job succeeded, so remove any backoff */
+ _backoff = 0;
+
+ return e;
+
+ } catch (std::exception& e) {
+ if (_backoff < 60) {
+ _backoff += 10;
+ }
+ LOG_ERROR (
+ N_("Remote encode of %1 on %2 failed (%3); thread sleeping for %4s"),
+ video->index(), _server.host_name(), e.what(), _backoff
+ );
+
+ boost::this_thread::sleep (boost::posix_time::seconds(_backoff));
+ return optional<Data>();
+ }
+}
+
diff --git a/src/lib/j2k_encoder_remote_backend.h b/src/lib/j2k_encoder_remote_backend.h
new file mode 100644
index 000000000..5e62cd9a9
--- /dev/null
+++ b/src/lib/j2k_encoder_remote_backend.h
@@ -0,0 +1,16 @@
+#include "encode_server_description.h"
+#include "j2k_encoder_backend.h"
+
+
+class J2KEncoderRemoteBackend : public J2KEncoderBackend
+{
+public:
+ J2KEncoderRemoteBackend (EncodeServerDescription server);
+ boost::optional<dcp::Data> encode (boost::shared_ptr<DCPVideo> video);
+
+private:
+ EncodeServerDescription _server;
+ int _backoff;
+};
+
+
diff --git a/src/lib/wscript b/src/lib/wscript
index 3b14f8738..59cc145a2 100644
--- a/src/lib/wscript
+++ b/src/lib/wscript
@@ -125,9 +125,11 @@ sources = """
image_proxy.cc
isdcf_metadata.cc
j2k_image_proxy.cc
+ j2k_encoder.cc
+ j2k_encoder_cpu_backend.cc
+ j2k_encoder_remote_backend.cc
job.cc
job_manager.cc
- j2k_encoder.cc
json_server.cc
kdm_with_metadata.cc
kdm_recipient.cc