From: Carl Hetherington Date: Mon, 17 Sep 2012 21:50:47 +0000 (+0100) Subject: Move server code into library; Server -> ServerDescription. X-Git-Tag: v2.0.48~1720^2~62 X-Git-Url: https://git.carlh.net/gitweb/?a=commitdiff_plain;h=1e8f1be709e8a3fa58f1147db2e58a39396313d8;p=dcpomatic.git Move server code into library; Server -> ServerDescription. --- diff --git a/src/lib/config.cc b/src/lib/config.cc index 53674645d..44d110689 100644 --- a/src/lib/config.cc +++ b/src/lib/config.cc @@ -76,7 +76,7 @@ Config::Config () } else if (k == "reference_filter") { _reference_filters.push_back (Filter::from_id (v)); } else if (k == "server") { - _servers.push_back (Server::create_from_metadata (v)); + _servers.push_back (ServerDescription::create_from_metadata (v)); } else if (k == "screen") { _screens.push_back (Screen::create_from_metadata (v)); } else if (k == "tms_ip") { @@ -131,7 +131,7 @@ Config::write () const f << "reference_filter " << (*i)->id () << "\n"; } - for (vector::const_iterator i = _servers.begin(); i != _servers.end(); ++i) { + for (vector::const_iterator i = _servers.begin(); i != _servers.end(); ++i) { f << "server " << (*i)->as_metadata () << "\n"; } diff --git a/src/lib/config.h b/src/lib/config.h index 14b541ee6..b002da7df 100644 --- a/src/lib/config.h +++ b/src/lib/config.h @@ -28,7 +28,7 @@ #include #include -class Server; +class ServerDescription; class Screen; class Scaler; class Filter; @@ -65,7 +65,7 @@ public: } /** @return J2K encoding servers to use */ - std::vector servers () const { + std::vector servers () const { return _servers; } @@ -126,7 +126,7 @@ public: } /** @param s New list of servers */ - void set_servers (std::vector s) { + void set_servers (std::vector s) { _servers = s; Changed (); } @@ -188,7 +188,7 @@ private: int _j2k_bandwidth; /** J2K encoding servers to use */ - std::vector _servers; + std::vector _servers; /** Screen definitions */ std::vector > _screens; diff --git a/src/lib/dcp_video_frame.cc b/src/lib/dcp_video_frame.cc index 24cdda2e6..91c441543 100644 --- a/src/lib/dcp_video_frame.cc +++ b/src/lib/dcp_video_frame.cc @@ -289,7 +289,7 @@ DCPVideoFrame::encode_locally () * @return Encoded data. */ shared_ptr -DCPVideoFrame::encode_remotely (Server const * serv) +DCPVideoFrame::encode_remotely (ServerDescription const * serv) { asio::io_service io_service; asio::ip::tcp::resolver resolver (io_service); diff --git a/src/lib/dcp_video_frame.h b/src/lib/dcp_video_frame.h index 464d48515..ee54bc0f5 100644 --- a/src/lib/dcp_video_frame.h +++ b/src/lib/dcp_video_frame.h @@ -27,7 +27,7 @@ class FilmState; class Options; -class Server; +class ServerDescription; class Scaler; class Image; class Log; @@ -113,7 +113,7 @@ public: virtual ~DCPVideoFrame (); boost::shared_ptr encode_locally (); - boost::shared_ptr encode_remotely (Server const *); + boost::shared_ptr encode_remotely (ServerDescription const *); int frame () const { return _frame; diff --git a/src/lib/j2k_wav_encoder.cc b/src/lib/j2k_wav_encoder.cc index 2f29f9021..ff450d1ad 100644 --- a/src/lib/j2k_wav_encoder.cc +++ b/src/lib/j2k_wav_encoder.cc @@ -130,7 +130,7 @@ J2KWAVEncoder::process_video (shared_ptr yuv, int frame) } void -J2KWAVEncoder::encoder_thread (Server* server) +J2KWAVEncoder::encoder_thread (ServerDescription* server) { /* Number of seconds that we currently wait between attempts to connect to the server; not relevant for localhost @@ -210,12 +210,12 @@ void J2KWAVEncoder::process_begin () { for (int i = 0; i < Config::instance()->num_local_encoding_threads (); ++i) { - _worker_threads.push_back (new boost::thread (boost::bind (&J2KWAVEncoder::encoder_thread, this, (Server *) 0))); + _worker_threads.push_back (new boost::thread (boost::bind (&J2KWAVEncoder::encoder_thread, this, (ServerDescription *) 0))); } - vector servers = Config::instance()->servers (); + vector servers = Config::instance()->servers (); - for (vector::iterator i = servers.begin(); i != servers.end(); ++i) { + for (vector::iterator i = servers.begin(); i != servers.end(); ++i) { for (int j = 0; j < (*i)->threads (); ++j) { _worker_threads.push_back (new boost::thread (boost::bind (&J2KWAVEncoder::encoder_thread, this, *i))); } diff --git a/src/lib/j2k_wav_encoder.h b/src/lib/j2k_wav_encoder.h index 656af8321..1c2f50065 100644 --- a/src/lib/j2k_wav_encoder.h +++ b/src/lib/j2k_wav_encoder.h @@ -29,7 +29,7 @@ #include #include "encoder.h" -class Server; +class ServerDescription; class DCPVideoFrame; class Image; class Log; @@ -50,7 +50,7 @@ public: private: - void encoder_thread (Server *); + void encoder_thread (ServerDescription *); void close_sound_files (); void terminate_worker_threads (); diff --git a/src/lib/log.h b/src/lib/log.h index d4de8ebde..d32b368f5 100644 --- a/src/lib/log.h +++ b/src/lib/log.h @@ -17,6 +17,9 @@ */ +#ifndef DVDOMATIC_LOG_H +#define DVDOMATIC_LOG_H + /** @file src/log.h * @brief A very simple logging class. */ @@ -53,3 +56,5 @@ private: /** level above which to ignore log messages */ Level _level; }; + +#endif diff --git a/src/lib/server.cc b/src/lib/server.cc index 8a5b5cfca..f4aaa25e1 100644 --- a/src/lib/server.cc +++ b/src/lib/server.cc @@ -19,7 +19,7 @@ /** @file src/server.cc * @brief Class to describe a server to which we can send - * encoding work. + * encoding work, and a class to implement such a server. */ #include @@ -27,16 +27,21 @@ #include #include #include "server.h" +#include "util.h" +#include "scaler.h" +#include "image.h" +#include "dcp_video_frame.h" +#include "config.h" using namespace std; using namespace boost; -/** Create a server from a string of metadata returned from as_metadata(). +/** Create a server description from a string of metadata returned from as_metadata(). * @param v Metadata. - * @return Server, or 0. + * @return ServerDescription, or 0. */ -Server * -Server::create_from_metadata (string v) +ServerDescription * +ServerDescription::create_from_metadata (string v) { vector b; split (b, v, is_any_of (" ")); @@ -45,14 +50,158 @@ Server::create_from_metadata (string v) return 0; } - return new Server (b[0], atoi (b[1].c_str ())); + return new ServerDescription (b[0], atoi (b[1].c_str ())); } /** @return Description of this server as text */ string -Server::as_metadata () const +ServerDescription::as_metadata () const { stringstream s; s << _host_name << " " << _threads; return s.str (); } + +Server::Server () + : _log ("servomatic.log") +{ + +} + +int +Server::process (shared_ptr socket) +{ + SocketReader reader (socket); + + char buffer[128]; + reader.read_indefinite ((uint8_t *) buffer, sizeof (buffer)); + reader.consume (strlen (buffer) + 1); + + stringstream s (buffer); + + string command; + s >> command; + if (command != "encode") { + return -1; + } + + Size in_size; + int pixel_format_int; + Size out_size; + int padding; + string scaler_id; + int frame; + float frames_per_second; + string post_process; + int colour_lut_index; + int j2k_bandwidth; + + s >> in_size.width >> in_size.height + >> pixel_format_int + >> out_size.width >> out_size.height + >> padding + >> scaler_id + >> frame + >> frames_per_second + >> post_process + >> colour_lut_index + >> j2k_bandwidth; + + PixelFormat pixel_format = (PixelFormat) pixel_format_int; + Scaler const * scaler = Scaler::from_id (scaler_id); + if (post_process == "none") { + post_process = ""; + } + + shared_ptr image (new SimpleImage (pixel_format, in_size)); + + for (int i = 0; i < image->components(); ++i) { + int line_size; + s >> line_size; + image->set_line_size (i, line_size); + } + + for (int i = 0; i < image->components(); ++i) { + reader.read_definite_and_consume (image->data()[i], image->line_size()[i] * image->lines(i)); + } + +#ifdef DEBUG_HASH + image->hash ("Image for encoding (as received by server)"); +#endif + + DCPVideoFrame dcp_video_frame (image, out_size, padding, scaler, frame, frames_per_second, post_process, colour_lut_index, j2k_bandwidth, &_log); + shared_ptr encoded = dcp_video_frame.encode_locally (); + encoded->send (socket); + +#ifdef DEBUG_HASH + encoded->hash ("Encoded image (as made by server and as sent back)"); +#endif + + return frame; +} + +void +Server::worker_thread () +{ + while (1) { + mutex::scoped_lock lock (_worker_mutex); + while (_queue.empty ()) { + _worker_condition.wait (lock); + } + + shared_ptr socket = _queue.front (); + _queue.pop_front (); + + lock.unlock (); + + int frame = -1; + + struct timeval start; + gettimeofday (&start, 0); + + try { + frame = process (socket); + } catch (std::exception& e) { + cerr << "Error: " << e.what() << "\n"; + } + + socket.reset (); + + lock.lock (); + + if (frame >= 0) { + struct timeval end; + gettimeofday (&end, 0); + cout << "Encoded frame " << frame << " in " << (seconds (end) - seconds (start)) << "\n"; + } + + _worker_condition.notify_all (); + } +} + +void +Server::run () +{ + int const num_threads = Config::instance()->num_local_encoding_threads (); + + for (int i = 0; i < num_threads; ++i) { + _worker_threads.push_back (new thread (bind (&Server::worker_thread, this))); + } + + asio::io_service io_service; + asio::ip::tcp::acceptor acceptor (io_service, asio::ip::tcp::endpoint (asio::ip::tcp::v4(), Config::instance()->server_port ())); + while (1) { + shared_ptr socket (new asio::ip::tcp::socket (io_service)); + acceptor.accept (*socket); + + mutex::scoped_lock lock (_worker_mutex); + + /* Wait until the queue has gone down a bit */ + while (int (_queue.size()) >= num_threads * 2) { + _worker_condition.wait (lock); + } + + _queue.push_back (socket); + _worker_condition.notify_all (); + } +} diff --git a/src/lib/server.h b/src/lib/server.h index d06df34e9..8c0f86ebb 100644 --- a/src/lib/server.h +++ b/src/lib/server.h @@ -19,21 +19,25 @@ /** @file src/server.h * @brief Class to describe a server to which we can send - * encoding work. + * encoding work, and a class to implement such a server. */ #include +#include +#include +#include +#include "log.h" -/** @class Server +/** @class ServerDescription * @brief Class to describe a server to which we can send encoding work. */ -class Server +class ServerDescription { public: /** @param h Server host name or IP address in string form. * @param t Number of threads to use on the server. */ - Server (std::string h, int t) + ServerDescription (std::string h, int t) : _host_name (h) , _threads (t) {} @@ -58,7 +62,7 @@ public: std::string as_metadata () const; - static Server * create_from_metadata (std::string v); + static ServerDescription * create_from_metadata (std::string v); private: /** server's host name */ @@ -66,3 +70,21 @@ private: /** number of threads to use on the server */ int _threads; }; + +class Server +{ +public: + Server (); + + void run (); + +private: + void worker_thread (); + int process (boost::shared_ptr socket); + + std::vector _worker_threads; + std::list > _queue; + boost::mutex _worker_mutex; + boost::condition _worker_condition; + Log _log; +}; diff --git a/src/tools/servomatic.cc b/src/tools/servomatic.cc deleted file mode 100644 index a9c45b3df..000000000 --- a/src/tools/servomatic.cc +++ /dev/null @@ -1,194 +0,0 @@ -/* - Copyright (C) 2012 Carl Hetherington - - This program 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. - - This program 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 this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - -*/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "config.h" -#include "dcp_video_frame.h" -#include "exceptions.h" -#include "util.h" -#include "config.h" -#include "scaler.h" -#include "image.h" -#include "log.h" - -#define BACKLOG 8 - -using namespace std; -using namespace boost; - -static vector worker_threads; - -static std::list > queue; -static mutex worker_mutex; -static condition worker_condition; -static Log log_ ("servomatic.log"); - -int -process (shared_ptr socket) -{ - SocketReader reader (socket); - - char buffer[128]; - reader.read_indefinite ((uint8_t *) buffer, sizeof (buffer)); - reader.consume (strlen (buffer) + 1); - - stringstream s (buffer); - - string command; - s >> command; - if (command != "encode") { - return -1; - } - - Size in_size; - int pixel_format_int; - Size out_size; - int padding; - string scaler_id; - int frame; - float frames_per_second; - string post_process; - int colour_lut_index; - int j2k_bandwidth; - - s >> in_size.width >> in_size.height - >> pixel_format_int - >> out_size.width >> out_size.height - >> padding - >> scaler_id - >> frame - >> frames_per_second - >> post_process - >> colour_lut_index - >> j2k_bandwidth; - - PixelFormat pixel_format = (PixelFormat) pixel_format_int; - Scaler const * scaler = Scaler::from_id (scaler_id); - if (post_process == "none") { - post_process = ""; - } - - shared_ptr image (new SimpleImage (pixel_format, in_size)); - - for (int i = 0; i < image->components(); ++i) { - int line_size; - s >> line_size; - image->set_line_size (i, line_size); - } - - for (int i = 0; i < image->components(); ++i) { - reader.read_definite_and_consume (image->data()[i], image->line_size()[i] * image->lines(i)); - } - -#ifdef DEBUG_HASH - image->hash ("Image for encoding (as received by server)"); -#endif - - DCPVideoFrame dcp_video_frame (image, out_size, padding, scaler, frame, frames_per_second, post_process, colour_lut_index, j2k_bandwidth, &log_); - shared_ptr encoded = dcp_video_frame.encode_locally (); - encoded->send (socket); - -#ifdef DEBUG_HASH - encoded->hash ("Encoded image (as made by server and as sent back)"); -#endif - - return frame; -} - -void -worker_thread () -{ - while (1) { - mutex::scoped_lock lock (worker_mutex); - while (queue.empty ()) { - worker_condition.wait (lock); - } - - shared_ptr socket = queue.front (); - queue.pop_front (); - - lock.unlock (); - - int frame = -1; - - struct timeval start; - gettimeofday (&start, 0); - - try { - frame = process (socket); - } catch (std::exception& e) { - cerr << "Error: " << e.what() << "\n"; - } - - socket.reset (); - - lock.lock (); - - if (frame >= 0) { - struct timeval end; - gettimeofday (&end, 0); - cout << "Encoded frame " << frame << " in " << (seconds (end) - seconds (start)) << "\n"; - } - - worker_condition.notify_all (); - } -} - -int -main () -{ - Scaler::setup_scalers (); - - int const num_threads = Config::instance()->num_local_encoding_threads (); - - for (int i = 0; i < num_threads; ++i) { - worker_threads.push_back (new thread (worker_thread)); - } - - asio::io_service io_service; - asio::ip::tcp::acceptor acceptor (io_service, asio::ip::tcp::endpoint (asio::ip::tcp::v4(), Config::instance()->server_port ())); - while (1) { - shared_ptr socket (new asio::ip::tcp::socket (io_service)); - acceptor.accept (*socket); - - mutex::scoped_lock lock (worker_mutex); - - /* Wait until the queue has gone down a bit */ - while (int (queue.size()) >= num_threads * 2) { - worker_condition.wait (lock); - } - - queue.push_back (socket); - worker_condition.notify_all (); - } - - return 0; -} diff --git a/src/tools/servomatic_cli.cc b/src/tools/servomatic_cli.cc new file mode 100644 index 000000000..1fcd02117 --- /dev/null +++ b/src/tools/servomatic_cli.cc @@ -0,0 +1,50 @@ +/* + Copyright (C) 2012 Carl Hetherington + + This program 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. + + This program 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 this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#include "lib/server.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "config.h" +#include "dcp_video_frame.h" +#include "exceptions.h" +#include "util.h" +#include "config.h" +#include "scaler.h" +#include "image.h" +#include "log.h" + +int +main () +{ + Scaler::setup_scalers (); + Server server; + server.run (); + return 0; +} diff --git a/src/tools/wscript b/src/tools/wscript index be3d44e6d..ff7134d15 100644 --- a/src/tools/wscript +++ b/src/tools/wscript @@ -1,5 +1,5 @@ def build(bld): - for t in ['makedcp', 'fixlengths', 'servomatic']: + for t in ['makedcp', 'fixlengths', 'servomatic_cli']: obj = bld(features = 'cxx cxxprogram') obj.uselib = 'BOOST_THREAD' obj.includes = ['..'] diff --git a/src/wx/config_dialog.cc b/src/wx/config_dialog.cc index b87f912b8..c53eeddf0 100644 --- a/src/wx/config_dialog.cc +++ b/src/wx/config_dialog.cc @@ -155,8 +155,8 @@ ConfigDialog::ConfigDialog (wxWindow* parent) _reference_filters->SetLabel (std_to_wx (p.first + " " + p.second)); _reference_filters_button->Connect (wxID_ANY, wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler (ConfigDialog::edit_reference_filters_clicked), 0, this); - vector servers = config->servers (); - for (vector::iterator i = servers.begin(); i != servers.end(); ++i) { + vector servers = config->servers (); + for (vector::iterator i = servers.begin(); i != servers.end(); ++i) { add_server_to_control (*i); } @@ -225,7 +225,7 @@ ConfigDialog::j2k_bandwidth_changed (wxCommandEvent &) } void -ConfigDialog::add_server_to_control (Server* s) +ConfigDialog::add_server_to_control (ServerDescription* s) { wxListItem item; int const n = _servers->GetItemCount (); @@ -240,11 +240,11 @@ ConfigDialog::add_server_clicked (wxCommandEvent &) { ServerDialog* d = new ServerDialog (this, 0); d->ShowModal (); - Server* s = d->server (); + ServerDescription* s = d->server (); d->Destroy (); add_server_to_control (s); - vector o = Config::instance()->servers (); + vector o = Config::instance()->servers (); o.push_back (s); Config::instance()->set_servers (o); } @@ -262,8 +262,8 @@ ConfigDialog::edit_server_clicked (wxCommandEvent &) item.SetColumn (0); _servers->GetItem (item); - vector servers = Config::instance()->servers (); - vector::iterator j = servers.begin(); + vector servers = Config::instance()->servers (); + vector::iterator j = servers.begin(); while (j != servers.end() && (*j)->host_name() != wx_to_std (item.GetText ())) { ++j; } diff --git a/src/wx/config_dialog.h b/src/wx/config_dialog.h index c9ca8034f..b1d3eb84d 100644 --- a/src/wx/config_dialog.h +++ b/src/wx/config_dialog.h @@ -26,7 +26,7 @@ #include class Screen; -class Server; +class ServerDescription; /** @class ConfigDialog * @brief A dialogue to edit DVD-o-matic configuration. @@ -52,7 +52,7 @@ private: void remove_server_clicked (wxCommandEvent &); void server_selection_changed (wxListEvent &); - void add_server_to_control (Server *); + void add_server_to_control (ServerDescription *); wxTextCtrl* _tms_ip; wxTextCtrl* _tms_path; diff --git a/src/wx/server_dialog.cc b/src/wx/server_dialog.cc index 0ae34b1fc..ad0f7a567 100644 --- a/src/wx/server_dialog.cc +++ b/src/wx/server_dialog.cc @@ -21,13 +21,13 @@ #include "server_dialog.h" #include "wx_util.h" -ServerDialog::ServerDialog (wxWindow* parent, Server* server) +ServerDialog::ServerDialog (wxWindow* parent, ServerDescription* server) : wxDialog (parent, wxID_ANY, wxString (_("Server"))) { if (server) { _server = server; } else { - _server = new Server ("localhost", 1); + _server = new ServerDescription ("localhost", 1); } wxFlexGridSizer* table = new wxFlexGridSizer (2, 4, 4); @@ -73,7 +73,7 @@ ServerDialog::threads_changed (wxCommandEvent &) _server->set_threads (_threads->GetValue ()); } -Server * +ServerDescription * ServerDialog::server () const { return _server; diff --git a/src/wx/server_dialog.h b/src/wx/server_dialog.h index 05630c377..0912fd60f 100644 --- a/src/wx/server_dialog.h +++ b/src/wx/server_dialog.h @@ -20,20 +20,20 @@ #include #include -class Server; +class ServerDescription; class ServerDialog : public wxDialog { public: - ServerDialog (wxWindow *, Server *); + ServerDialog (wxWindow *, ServerDescription *); - Server* server () const; + ServerDescription* server () const; private: void host_changed (wxCommandEvent &); void threads_changed (wxCommandEvent &); - Server* _server; + ServerDescription* _server; wxTextCtrl* _host; wxSpinCtrl* _threads; };