Extract audio more correctly and neatly; support 7.1 in DCP naming; fix up lack of...
[dcpomatic.git] / src / lib / server.cc
index f4aaa25e128ec193c3c49939bd4419ef1e11997e..10f64b48250ee044e87128d45b7c5db8fe85e3c3 100644 (file)
 #include <string>
 #include <vector>
 #include <sstream>
+#include <iostream>
 #include <boost/algorithm/string.hpp>
+#include <boost/lexical_cast.hpp>
 #include "server.h"
 #include "util.h"
 #include "scaler.h"
 #include "image.h"
 #include "dcp_video_frame.h"
 #include "config.h"
+#include "subtitle.h"
 
 using namespace std;
 using namespace boost;
@@ -62,81 +65,66 @@ ServerDescription::as_metadata () const
        return s.str ();
 }
 
-Server::Server ()
-       : _log ("servomatic.log")
+Server::Server (Log* log)
+       : _log (log)
 {
 
 }
 
 int
-Server::process (shared_ptr<asio::ip::tcp::socket> socket)
+Server::process (shared_ptr<Socket> socket)
 {
-       SocketReader reader (socket);
-       
-       char buffer[128];
-       reader.read_indefinite ((uint8_t *) buffer, sizeof (buffer));
-       reader.consume (strlen (buffer) + 1);
+       char buffer[512];
+       socket->read_indefinite ((uint8_t *) buffer, sizeof (buffer), 30);
+       socket->consume (strlen (buffer) + 1);
        
        stringstream s (buffer);
-       
-       string command;
-       s >> command;
-       if (command != "encode") {
+       multimap<string, string> kv = read_key_value (s);
+
+       if (get_required_string (kv, "encode") != "please") {
                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;
-       
+
+       Size in_size (get_required_int (kv, "input_width"), get_required_int (kv, "input_height"));
+       int pixel_format_int = get_required_int (kv, "input_pixel_format");
+       Size out_size (get_required_int (kv, "output_width"), get_required_int (kv, "output_height"));
+       int padding = get_required_int (kv, "padding");
+       int subtitle_offset = get_required_int (kv, "subtitle_offset");
+       float subtitle_scale = get_required_float (kv, "subtitle_scale");
+       string scaler_id = get_required_string (kv, "scaler");
+       int frame = get_required_int (kv, "frame");
+       int frames_per_second = get_required_int (kv, "frames_per_second");
+       string post_process = get_optional_string (kv, "post_process");
+       int colour_lut_index = get_required_int (kv, "colour_lut");
+       int j2k_bandwidth = get_required_int (kv, "j2k_bandwidth");
+       Position subtitle_position (get_optional_int (kv, "subtitle_x"), get_optional_int (kv, "subtitle_y"));
+       Size subtitle_size (get_optional_int (kv, "subtitle_width"), get_optional_int (kv, "subtitle_height"));
+
+       /* This checks that colour_lut_index is within range */
+       colour_lut_index_to_name (colour_lut_index);
+
        PixelFormat pixel_format = (PixelFormat) pixel_format_int;
        Scaler const * scaler = Scaler::from_id (scaler_id);
-       if (post_process == "none") {
-               post_process = "";
-       }
-       
-       shared_ptr<SimpleImage> 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));
+       shared_ptr<Image> image (new AlignedImage (pixel_format, in_size));
+
+       image->read_from_socket (socket);
+
+       shared_ptr<Subtitle> sub;
+       if (subtitle_size.width && subtitle_size.height) {
+               shared_ptr<Image> subtitle_image (new AlignedImage (PIX_FMT_RGBA, subtitle_size));
+               subtitle_image->read_from_socket (socket);
+               sub.reset (new Subtitle (subtitle_position, subtitle_image));
        }
+
+       DCPVideoFrame dcp_video_frame (
+               image, sub, out_size, padding, subtitle_offset, subtitle_scale,
+               scaler, frame, frames_per_second, post_process, colour_lut_index, j2k_bandwidth, _log
+               );
        
-#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<EncodedData> 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;
 }
 
@@ -149,7 +137,7 @@ Server::worker_thread ()
                        _worker_condition.wait (lock);
                }
 
-               shared_ptr<asio::ip::tcp::socket> socket = _queue.front ();
+               shared_ptr<Socket> socket = _queue.front ();
                _queue.pop_front ();
                
                lock.unlock ();
@@ -172,7 +160,7 @@ Server::worker_thread ()
                if (frame >= 0) {
                        struct timeval end;
                        gettimeofday (&end, 0);
-                       cout << "Encoded frame " << frame << " in " << (seconds (end) - seconds (start)) << "\n";
+                       _log->log (String::compose ("Encoded frame %1 in %2", frame, seconds (end) - seconds (start)));
                }
                
                _worker_condition.notify_all ();
@@ -180,19 +168,19 @@ Server::worker_thread ()
 }
 
 void
-Server::run ()
+Server::run (int num_threads)
 {
-       int const num_threads = Config::instance()->num_local_encoding_threads ();
+       _log->log (String::compose ("Server starting with %1 threads", num_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<asio::ip::tcp::socket> socket (new asio::ip::tcp::socket (io_service));
-               acceptor.accept (*socket);
+               shared_ptr<Socket> socket (new Socket);
+               acceptor.accept (socket->socket ());
 
                mutex::scoped_lock lock (_worker_mutex);