Make DCPVideoFrame use PlayerVideoFrame to store its image.
authorCarl Hetherington <cth@carlh.net>
Wed, 14 May 2014 18:27:04 +0000 (19:27 +0100)
committerCarl Hetherington <cth@carlh.net>
Wed, 14 May 2014 18:27:04 +0000 (19:27 +0100)
15 files changed:
src/lib/colour_conversion.cc
src/lib/dcp_video_frame.cc
src/lib/dcp_video_frame.h
src/lib/encoder.cc
src/lib/image.cc
src/lib/image.h
src/lib/player_video_frame.cc
src/lib/player_video_frame.h
src/lib/server.cc
src/lib/types.cc
src/lib/types.h
src/lib/video_content.cc
src/lib/writer.h
src/tools/server_test.cc
test/client_server_test.cc

index cd1a81b257dcadfa76b1c6196ae7e7267f9dfce6..5f17f9184c9dfb6bfb10fdd195ad6f8cd5432338 100644 (file)
@@ -29,6 +29,7 @@
 
 using std::list;
 using std::string;
+using std::stringstream;
 using std::cout;
 using std::vector;
 using boost::shared_ptr;
index 1c12eb7fd7b9a6022de7e0a1b26895d3256669b7..5cd6a118e6256987646734b0a2d47b4187872ac3 100644 (file)
@@ -42,6 +42,7 @@
 #include <boost/array.hpp>
 #include <boost/asio.hpp>
 #include <boost/filesystem.hpp>
+#include <openssl/md5.h>
 #include <libdcp/rec709_linearised_gamma_lut.h>
 #include <libdcp/srgb_linearised_gamma_lut.h>
 #include <libdcp/gamma_lut.h>
@@ -60,6 +61,7 @@
 #include "image.h"
 #include "log.h"
 #include "cross.h"
+#include "player_video_frame.h"
 
 #include "i18n.h"
 
@@ -73,18 +75,16 @@ using libdcp::raw_convert;
 #define DCI_COEFFICENT (48.0 / 52.37)
 
 /** Construct a DCP video frame.
- *  @param input Input image.
- *  @param f Index of the frame within the DCP.
+ *  @param frame Input frame.
+ *  @param index Index of the frame within the DCP.
  *  @param bw J2K bandwidth to use (see Config::j2k_bandwidth ())
  *  @param l Log to write to.
  */
 DCPVideoFrame::DCPVideoFrame (
-       shared_ptr<const Image> image, int f, Eyes eyes, ColourConversion c, int dcp_fps, int bw, Resolution r, shared_ptr<Log> l
+       shared_ptr<const PlayerVideoFrame> frame, int index, int dcp_fps, int bw, Resolution r, shared_ptr<Log> l
        )
-       : _image (image)
-       , _frame (f)
-       , _eyes (eyes)
-       , _conversion (c)
+       : _frame (frame)
+       , _index (index)
        , _frames_per_second (dcp_fps)
        , _j2k_bandwidth (bw)
        , _resolution (r)
@@ -93,22 +93,11 @@ DCPVideoFrame::DCPVideoFrame (
        
 }
 
-DCPVideoFrame::DCPVideoFrame (shared_ptr<const Image> image, shared_ptr<const cxml::Node> node, shared_ptr<Log> log)
-       : _image (image)
+DCPVideoFrame::DCPVideoFrame (shared_ptr<const PlayerVideoFrame> frame, shared_ptr<const cxml::Node> node, shared_ptr<Log> log)
+       : _frame (frame)
        , _log (log)
 {
-       _frame = node->number_child<int> ("Frame");
-       string const eyes = node->string_child ("Eyes");
-       if (eyes == "Both") {
-               _eyes = EYES_BOTH;
-       } else if (eyes == "Left") {
-               _eyes = EYES_LEFT;
-       } else if (eyes == "Right") {
-               _eyes = EYES_RIGHT;
-       } else {
-               assert (false);
-       }
-       _conversion = ColourConversion (node->node_child ("ColourConversion"));
+       _index = node->number_child<int> ("Index");
        _frames_per_second = node->number_child<int> ("FramesPerSecond");
        _j2k_bandwidth = node->number_child<int> ("J2KBandwidth");
        _resolution = Resolution (node->optional_number_child<int>("Resolution").get_value_or (RESOLUTION_2K));
@@ -121,10 +110,10 @@ shared_ptr<EncodedData>
 DCPVideoFrame::encode_locally ()
 {
        shared_ptr<libdcp::LUT> in_lut;
-       if (_conversion.input_gamma_linearised) {
-               in_lut = libdcp::SRGBLinearisedGammaLUT::cache.get (12, _conversion.input_gamma);
+       if (_frame->colour_conversion().input_gamma_linearised) {
+               in_lut = libdcp::SRGBLinearisedGammaLUT::cache.get (12, _frame->colour_conversion().input_gamma);
        } else {
-               in_lut = libdcp::GammaLUT::cache.get (12, _conversion.input_gamma);
+               in_lut = libdcp::GammaLUT::cache.get (12, _frame->colour_conversion().input_gamma);
        }
 
        /* XXX: libdcp should probably use boost */
@@ -132,20 +121,35 @@ DCPVideoFrame::encode_locally ()
        double matrix[3][3];
        for (int i = 0; i < 3; ++i) {
                for (int j = 0; j < 3; ++j) {
-                       matrix[i][j] = _conversion.matrix (i, j);
+                       matrix[i][j] = _frame->colour_conversion().matrix (i, j);
                }
        }
-       
+
        shared_ptr<libdcp::XYZFrame> xyz = libdcp::rgb_to_xyz (
-               _image,
+               _frame->image(),
                in_lut,
-               libdcp::GammaLUT::cache.get (16, 1 / _conversion.output_gamma),
+               libdcp::GammaLUT::cache.get (16, 1 / _frame->colour_conversion().output_gamma),
                matrix
                );
+
+       {
+               MD5_CTX md5_context;
+               MD5_Init (&md5_context);
+               MD5_Update (&md5_context, xyz->data(0), 1998 * 1080 * 4);
+               MD5_Update (&md5_context, xyz->data(1), 1998 * 1080 * 4);
+               MD5_Update (&md5_context, xyz->data(2), 1998 * 1080 * 4);
+               unsigned char digest[MD5_DIGEST_LENGTH];
+               MD5_Final (digest, &md5_context);
                
+               stringstream s;
+               for (int i = 0; i < MD5_DIGEST_LENGTH; ++i) {
+                       s << std::hex << std::setfill('0') << std::setw(2) << ((int) digest[i]);
+               }
+       }
+
        /* Set the max image and component sizes based on frame_rate */
        int max_cs_len = ((float) _j2k_bandwidth) / 8 / _frames_per_second;
-       if (_eyes == EYES_LEFT || _eyes == EYES_RIGHT) {
+       if (_frame->eyes() == EYES_LEFT || _frame->eyes() == EYES_RIGHT) {
                /* In 3D we have only half the normal bandwidth per eye */
                max_cs_len /= 2;
        }
@@ -244,15 +248,15 @@ DCPVideoFrame::encode_locally ()
                throw EncodeError (N_("JPEG2000 encoding failed"));
        }
 
-       switch (_eyes) {
+       switch (_frame->eyes()) {
        case EYES_BOTH:
-               _log->log (String::compose (N_("Finished locally-encoded frame %1 for mono"), _frame));
+               _log->log (String::compose (N_("Finished locally-encoded frame %1 for mono"), _index));
                break;
        case EYES_LEFT:
-               _log->log (String::compose (N_("Finished locally-encoded frame %1 for L"), _frame));
+               _log->log (String::compose (N_("Finished locally-encoded frame %1 for L"), _index));
                break;
        case EYES_RIGHT:
-               _log->log (String::compose (N_("Finished locally-encoded frame %1 for R"), _frame));
+               _log->log (String::compose (N_("Finished locally-encoded frame %1 for R"), _index));
                break;
        default:
                break;
@@ -283,28 +287,30 @@ DCPVideoFrame::encode_remotely (ServerDescription serv)
 
        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));
-       root->add_child("Width")->add_child_text (raw_convert<string> (_image->size().width));
-       root->add_child("Height")->add_child_text (raw_convert<string> (_image->size().height));
        add_metadata (root);
 
+       _log->log (String::compose (N_("Sending frame %1 to remote"), _index));
+       
+       /* Send XML metadata */
        stringstream xml;
        doc.write_to_stream (xml, "UTF-8");
-
-       _log->log (String::compose (N_("Sending frame %1 to remote"), _frame));
-
        socket->write (xml.str().length() + 1);
        socket->write ((uint8_t *) xml.str().c_str(), xml.str().length() + 1);
 
-       _image->write_to_socket (socket);
+       /* Send binary data */
+       _frame->send_binary (socket);
 
+       /* Read the response (JPEG2000-encoded data); this blocks until the data
+          is ready and sent back.
+       */
        shared_ptr<EncodedData> e (new RemotelyEncodedData (socket->read_uint32 ()));
        socket->read (e->data(), e->size());
 
-       _log->log (String::compose (N_("Finished remotely-encoded frame %1"), _frame));
+       _log->log (String::compose (N_("Finished remotely-encoded frame %1"), _index));
        
        return e;
 }
@@ -312,27 +318,17 @@ DCPVideoFrame::encode_remotely (ServerDescription serv)
 void
 DCPVideoFrame::add_metadata (xmlpp::Element* el) const
 {
-       el->add_child("Frame")->add_child_text (raw_convert<string> (_frame));
-
-       switch (_eyes) {
-       case EYES_BOTH:
-               el->add_child("Eyes")->add_child_text ("Both");
-               break;
-       case EYES_LEFT:
-               el->add_child("Eyes")->add_child_text ("Left");
-               break;
-       case EYES_RIGHT:
-               el->add_child("Eyes")->add_child_text ("Right");
-               break;
-       default:
-               assert (false);
-       }
-       
-       _conversion.as_xml (el->add_child("ColourConversion"));
-
+       el->add_child("Index")->add_child_text (raw_convert<string> (_index));
        el->add_child("FramesPerSecond")->add_child_text (raw_convert<string> (_frames_per_second));
        el->add_child("J2KBandwidth")->add_child_text (raw_convert<string> (_j2k_bandwidth));
        el->add_child("Resolution")->add_child_text (raw_convert<string> (int (_resolution)));
+       _frame->add_metadata (el);
+}
+
+Eyes
+DCPVideoFrame::eyes () const
+{
+       return _frame->eyes ();
 }
 
 EncodedData::EncodedData (int s)
index 40f758c7423ab855e07ac3991984bfa559eeef1d..e4006d98683af8c9ff58e9d0eafc9040686d9c56 100644 (file)
@@ -1,5 +1,5 @@
 /*
-    Copyright (C) 2012 Carl Hetherington <cth@carlh.net>
+    Copyright (C) 2012-2014 Carl Hetherington <cth@carlh.net>
     Taken from code Copyright (C) 2010-2011 Terrence Meiczinger
 
     This program is free software; you can redistribute it and/or modify
@@ -33,6 +33,7 @@ class Scaler;
 class Image;
 class Log;
 class Subtitle;
+class PlayerVideoFrame;
 
 /** @class EncodedData
  *  @brief Container for J2K-encoded data.
@@ -102,28 +103,24 @@ public:
 class DCPVideoFrame : public boost::noncopyable
 {
 public:
-       DCPVideoFrame (boost::shared_ptr<const Image>, int, Eyes, ColourConversion, int, int, Resolution, boost::shared_ptr<Log>);
-       DCPVideoFrame (boost::shared_ptr<const Image>, boost::shared_ptr<const cxml::Node>, boost::shared_ptr<Log>);
+       DCPVideoFrame (boost::shared_ptr<const PlayerVideoFrame>, int, int, int, Resolution, boost::shared_ptr<Log>);
+       DCPVideoFrame (boost::shared_ptr<const PlayerVideoFrame>, boost::shared_ptr<const cxml::Node>, boost::shared_ptr<Log>);
 
        boost::shared_ptr<EncodedData> encode_locally ();
        boost::shared_ptr<EncodedData> encode_remotely (ServerDescription);
 
-       Eyes eyes () const {
-               return _eyes;
-       }
-       
-       int frame () const {
-               return _frame;
+       int index () const {
+               return _index;
        }
+
+       Eyes eyes () const;
        
 private:
 
        void add_metadata (xmlpp::Element *) const;
        
-       boost::shared_ptr<const Image> _image;
-       int _frame;                      ///< frame index within the DCP's intrinsic duration
-       Eyes _eyes;
-       ColourConversion _conversion;
+       boost::shared_ptr<const PlayerVideoFrame> _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
        int _j2k_bandwidth;              ///< J2K bandwidth to use
        Resolution _resolution;          ///< Resolution (2K or 4K)
index 8ae402797cf31d91c2f0ac6a3a5e9682c3b8664b..4fc2d7f81c152b760d00b0a8e0db79c2dd307c0c 100644 (file)
@@ -125,9 +125,9 @@ Encoder::process_end ()
        */
 
        for (list<shared_ptr<DCPVideoFrame> >::iterator i = _queue.begin(); i != _queue.end(); ++i) {
-               _film->log()->log (String::compose (N_("Encode left-over frame %1"), (*i)->frame ()));
+               _film->log()->log (String::compose (N_("Encode left-over frame %1"), (*i)->index ()));
                try {
-                       _writer->write ((*i)->encode_locally(), (*i)->frame (), (*i)->eyes ());
+                       _writer->write ((*i)->encode_locally(), (*i)->index (), (*i)->eyes ());
                        frame_done ();
                } catch (std::exception& e) {
                        _film->log()->log (String::compose (N_("Local encode failed (%1)"), e.what ()));
@@ -219,7 +219,7 @@ Encoder::process_video (shared_ptr<PlayerVideoFrame> pvf, bool same)
                TIMING ("adding to queue of %1", _queue.size ());
                _queue.push_back (shared_ptr<DCPVideoFrame> (
                                          new DCPVideoFrame (
-                                                 pvf->image(), _video_frames_out, pvf->eyes(), pvf->colour_conversion(), _film->video_frame_rate(),
+                                                 pvf, _video_frames_out, _film->video_frame_rate(),
                                                  _film->j2k_bandwidth(), _film->resolution(), _film->log()
                                                  )
                                          ));
@@ -282,7 +282,7 @@ try
 
                TIMING ("encoder thread %1 wakes with queue of %2", boost::this_thread::get_id(), _queue.size());
                shared_ptr<DCPVideoFrame> vf = _queue.front ();
-               TIMING ("encoder thread %1 pops frame %2 (%3) from queue", boost::this_thread::get_id(), vf->frame(), vf->eyes ());
+               TIMING ("encoder thread %1 pops frame %2 (%3) from queue", boost::this_thread::get_id(), vf->index(), vf->eyes ());
                _queue.pop_front ();
                
                lock.unlock ();
@@ -308,27 +308,27 @@ try
                                _film->log()->log (
                                        String::compose (
                                                N_("Remote encode of %1 on %2 failed (%3); thread sleeping for %4s"),
-                                               vf->frame(), server->host_name(), e.what(), remote_backoff)
+                                               vf->index(), server->host_name(), e.what(), remote_backoff)
                                        );
                        }
                                
                } else {
                        try {
-                               TIMING ("encoder thread %1 begins local encode of %2", boost::this_thread::get_id(), vf->frame());
+                               TIMING ("encoder thread %1 begins local encode of %2", boost::this_thread::get_id(), vf->index());
                                encoded = vf->encode_locally ();
-                               TIMING ("encoder thread %1 finishes local encode of %2", boost::this_thread::get_id(), vf->frame());
+                               TIMING ("encoder thread %1 finishes local encode of %2", boost::this_thread::get_id(), vf->index());
                        } catch (std::exception& e) {
                                _film->log()->log (String::compose (N_("Local encode failed (%1)"), e.what ()));
                        }
                }
 
                if (encoded) {
-                       _writer->write (encoded, vf->frame (), vf->eyes ());
+                       _writer->write (encoded, vf->index (), vf->eyes ());
                        frame_done ();
                } else {
                        lock.lock ();
                        _film->log()->log (
-                               String::compose (N_("Encoder thread %1 pushes frame %2 back onto queue after failure"), boost::this_thread::get_id(), vf->frame())
+                               String::compose (N_("Encoder thread %1 pushes frame %2 back onto queue after failure"), boost::this_thread::get_id(), vf->index())
                                );
                        _queue.push_front (vf);
                        lock.unlock ();
index d083cf3f6c17612caa6e249cf86413116f655667..1fa55e24209ed099ba43bf03cda8693c13e57067 100644 (file)
@@ -22,6 +22,7 @@
  */
 
 #include <iostream>
+#include <openssl/md5.h>
 extern "C" {
 #include <libswscale/swscale.h>
 #include <libavutil/pixfmt.h>
@@ -37,6 +38,7 @@ using std::string;
 using std::min;
 using std::cout;
 using std::cerr;
+using std::stringstream;
 using boost::shared_ptr;
 using libdcp::Size;
 
@@ -619,3 +621,24 @@ Image::aligned () const
        return _aligned;
 }
 
+string
+Image::digest () const
+{
+       MD5_CTX md5_context;
+       MD5_Init (&md5_context);
+
+       for (int i = 0; i < components(); ++i) {
+               MD5_Update (&md5_context, data()[i], line_size()[i]);
+       }
+       
+       unsigned char digest[MD5_DIGEST_LENGTH];
+       MD5_Final (digest, &md5_context);
+       
+       stringstream s;
+       for (int i = 0; i < MD5_DIGEST_LENGTH; ++i) {
+               s << std::hex << std::setfill('0') << std::setw(2) << ((int) digest[i]);
+       }
+
+       return s.str ();
+}
+       
index 2d9f322310c2c3e66d5a9d4e05f9c88deffb3b51..f83bf6998111defbb49fcd49d67dea6703099992 100644 (file)
@@ -73,6 +73,8 @@ public:
                return _pixel_format;
        }
 
+       std::string digest () const;
+
 private:
        friend class pixel_formats_test;
        
index 571c18b6e5dfa2b6a38e9829ffa5ede95012bc65..cbe879d10e9ae1eca5b40726a20e945e9df678ca 100644 (file)
 
 */
 
+#include <libdcp/raw_convert.h>
 #include "player_video_frame.h"
 #include "image.h"
+#include "scaler.h"
 
+using std::string;
+using std::cout;
 using boost::shared_ptr;
+using libdcp::raw_convert;
 
 PlayerVideoFrame::PlayerVideoFrame (
        shared_ptr<const Image> in,
@@ -42,6 +47,33 @@ PlayerVideoFrame::PlayerVideoFrame (
 
 }
 
+PlayerVideoFrame::PlayerVideoFrame (shared_ptr<cxml::Node> node, shared_ptr<Socket> socket)
+{
+       _crop = Crop (node);
+
+       _inter_size = libdcp::Size (node->number_child<int> ("InterWidth"), node->number_child<int> ("InterHeight"));
+       _out_size = libdcp::Size (node->number_child<int> ("OutWidth"), node->number_child<int> ("OutHeight"));
+       _scaler = Scaler::from_id (node->string_child ("Scaler"));
+       _eyes = (Eyes) node->number_child<int> ("Eyes");
+       _colour_conversion = ColourConversion (node);
+
+       shared_ptr<Image> image (new Image (PIX_FMT_RGB24, libdcp::Size (node->number_child<int> ("InWidth"), node->number_child<int> ("InHeight")), true));
+       image->read_from_socket (socket);
+       _in = image;
+
+       if (node->optional_number_child<int> ("SubtitleX")) {
+               
+               _subtitle_position = Position<int> (node->number_child<int> ("SubtitleX"), node->number_child<int> ("SubtitleY"));
+
+               shared_ptr<Image> image (
+                       new Image (PIX_FMT_RGBA, libdcp::Size (node->number_child<int> ("SubtitleWidth"), node->number_child<int> ("SubtitleHeight")), true)
+                       );
+               
+               image->read_from_socket (socket);
+               _subtitle_image = image;
+       }
+}
+
 void
 PlayerVideoFrame::set_subtitle (shared_ptr<const Image> image, Position<int> pos)
 {
@@ -50,7 +82,7 @@ PlayerVideoFrame::set_subtitle (shared_ptr<const Image> image, Position<int> pos
 }
 
 shared_ptr<Image>
-PlayerVideoFrame::image ()
+PlayerVideoFrame::image () const
 {
        shared_ptr<Image> out = _in->crop_scale_window (_crop, _inter_size, _out_size, _scaler, PIX_FMT_RGB24, false);
 
@@ -62,3 +94,33 @@ PlayerVideoFrame::image ()
 
        return out;
 }
+
+void
+PlayerVideoFrame::add_metadata (xmlpp::Element* node) const
+{
+       _crop.as_xml (node);
+       node->add_child("InWidth")->add_child_text (raw_convert<string> (_in->size().width));
+       node->add_child("InHeight")->add_child_text (raw_convert<string> (_in->size().height));
+       node->add_child("InterWidth")->add_child_text (raw_convert<string> (_inter_size.width));
+       node->add_child("InterHeight")->add_child_text (raw_convert<string> (_inter_size.height));
+       node->add_child("OutWidth")->add_child_text (raw_convert<string> (_out_size.width));
+       node->add_child("OutHeight")->add_child_text (raw_convert<string> (_out_size.height));
+       node->add_child("Scaler")->add_child_text (_scaler->id ());
+       node->add_child("Eyes")->add_child_text (raw_convert<string> (_eyes));
+       _colour_conversion.as_xml (node);
+       if (_subtitle_image) {
+               node->add_child ("SubtitleWidth")->add_child_text (raw_convert<string> (_subtitle_image->size().width));
+               node->add_child ("SubtitleHeight")->add_child_text (raw_convert<string> (_subtitle_image->size().height));
+               node->add_child ("SubtitleX")->add_child_text (raw_convert<string> (_subtitle_position.x));
+               node->add_child ("SubtitleY")->add_child_text (raw_convert<string> (_subtitle_position.y));
+       }
+}
+
+void
+PlayerVideoFrame::send_binary (shared_ptr<Socket> socket) const
+{
+       _in->write_to_socket (socket);
+       if (_subtitle_image) {
+               _subtitle_image->write_to_socket (socket);
+       }
+}
index 42d345c9ab586ec3885a2add249bb098bce460f3..ea7e544819be8c1b822ac9fb8c11b65bf1989845 100644 (file)
@@ -24,6 +24,7 @@
 
 class Image;
 class Scaler;
+class Socket;
 
 /** Everything needed to describe a video frame coming out of the player, but with the
  *  bits still their raw form.  We may want to combine the bits on a remote machine,
@@ -33,10 +34,14 @@ class PlayerVideoFrame
 {
 public:
        PlayerVideoFrame (boost::shared_ptr<const Image>, Crop, libdcp::Size, libdcp::Size, Scaler const *, Eyes, ColourConversion);
+       PlayerVideoFrame (boost::shared_ptr<cxml::Node>, boost::shared_ptr<Socket>);
 
        void set_subtitle (boost::shared_ptr<const Image>, Position<int>);
        
-       boost::shared_ptr<Image> image ();
+       boost::shared_ptr<Image> image () const;
+
+       void add_metadata (xmlpp::Element* node) const;
+       void send_binary (boost::shared_ptr<Socket> socket) const;
 
        Eyes eyes () const {
                return _eyes;
index 0c5792ae0da6b8d07d678e5244b6b04b381645e6..b9bb825ee051f4694d6a61be522d5a8a851a4b86 100644 (file)
@@ -1,5 +1,5 @@
 /*
-    Copyright (C) 2012 Carl Hetherington <cth@carlh.net>
+    Copyright (C) 2012-2014 Carl Hetherington <cth@carlh.net>
 
     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
@@ -37,6 +37,7 @@
 #include "dcp_video_frame.h"
 #include "config.h"
 #include "cross.h"
+#include "player_video_frame.h"
 
 #include "i18n.h"
 
@@ -75,7 +76,7 @@ Server::process (shared_ptr<Socket> socket, struct timeval& after_read, struct t
        uint32_t length = socket->read_uint32 ();
        scoped_array<char> buffer (new char[length]);
        socket->read (reinterpret_cast<uint8_t*> (buffer.get()), length);
-       
+
        stringstream s (buffer.get());
        shared_ptr<cxml::Document> xml (new cxml::Document ("EncodingRequest"));
        xml->read_stream (s);
@@ -85,14 +86,9 @@ Server::process (shared_ptr<Socket> socket, struct timeval& after_read, struct t
                return -1;
        }
 
-       libdcp::Size size (
-               xml->number_child<int> ("Width"), xml->number_child<int> ("Height")
-               );
-
-       shared_ptr<Image> image (new Image (PIX_FMT_RGB24, size, true));
+       shared_ptr<PlayerVideoFrame> pvf (new PlayerVideoFrame (xml, socket));
 
-       image->read_from_socket (socket);
-       DCPVideoFrame dcp_video_frame (image, xml, _log);
+       DCPVideoFrame dcp_video_frame (pvf, xml, _log);
 
        gettimeofday (&after_read, 0);
        
@@ -103,15 +99,11 @@ Server::process (shared_ptr<Socket> socket, struct timeval& after_read, struct t
        try {
                encoded->send (socket);
        } catch (std::exception& e) {
-               _log->log (String::compose (
-                                  "Send failed; frame %1, data size %2, pixel format %3, image size %4x%5, %6 components",
-                                  dcp_video_frame.frame(), encoded->size(), image->pixel_format(), image->size().width, image->size().height, image->components()
-                                  )
-                       );
+               _log->log (String::compose ("Send failed; frame %1", dcp_video_frame.index()));
                throw;
        }
 
-       return dcp_video_frame.frame ();
+       return dcp_video_frame.index ();
 }
 
 void
index bc4f5f8d9d425d0d9305f1015c124ee92590dcb7..83bbf41e45c19125e779b4be18f6a48e9b2a5cd0 100644 (file)
 
 */
 
+#include <libxml++/libxml++.h>
+#include <libcxml/cxml.h>
+#include <libdcp/raw_convert.h>
 #include "types.h"
 
 using std::max;
 using std::min;
 using std::string;
+using boost::shared_ptr;
+using libdcp::raw_convert;
 
 bool operator== (Crop const & a, Crop const & b)
 {
@@ -65,3 +70,20 @@ string_to_resolution (string s)
        assert (false);
        return RESOLUTION_2K;
 }
+
+Crop::Crop (shared_ptr<cxml::Node> node)
+{
+       left = node->number_child<int> ("LeftCrop");
+       right = node->number_child<int> ("RightCrop");
+       top = node->number_child<int> ("TopCrop");
+       bottom = node->number_child<int> ("BottomCrop");
+}
+
+void
+Crop::as_xml (xmlpp::Node* node) const
+{
+       node->add_child("LeftCrop")->add_child_text (raw_convert<string> (left));
+       node->add_child("RightCrop")->add_child_text (raw_convert<string> (right));
+       node->add_child("TopCrop")->add_child_text (raw_convert<string> (top));
+       node->add_child("BottomCrop")->add_child_text (raw_convert<string> (bottom));
+}
index c255bd0d8a43acd6c80a9a5a38f4040fa0e82dca..8e2384d804cc08df409c2e01fcd2373dc7032fdc 100644 (file)
@@ -32,11 +32,19 @@ class SubtitleContent;
 class FFmpegContent;
 class AudioBuffers;
 
+namespace cxml {
+       class Node;
+}
+
+namespace xmlpp {
+       class Node;
+}
+
 /** The version number of the protocol used to communicate
  *  with servers.  Intended to be bumped when incompatibilities
  *  are introduced.
  */
-#define SERVER_LINK_VERSION 1
+#define SERVER_LINK_VERSION 2
 
 typedef int64_t Time;
 #define TIME_MAX INT64_MAX
@@ -92,6 +100,7 @@ struct Crop
 {
        Crop () : left (0), right (0), top (0), bottom (0) {}
        Crop (int l, int r, int t, int b) : left (l), right (r), top (t), bottom (b) {}
+       Crop (boost::shared_ptr<cxml::Node>);
 
        /** Number of pixels to remove from the left-hand side */
        int left;
@@ -116,6 +125,8 @@ struct Crop
                
                return s;
        }
+
+       void as_xml (xmlpp::Node *) const;
 };
 
 extern bool operator== (Crop const & a, Crop const & b);
index 783cddafad958fcb5ee81cc3806bea3dc2dff8e8..40772980fb466754fdec79cd85699a082b33c7ae 100644 (file)
@@ -161,10 +161,7 @@ VideoContent::as_xml (xmlpp::Node* node) const
        node->add_child("VideoHeight")->add_child_text (raw_convert<string> (_video_size.height));
        node->add_child("VideoFrameRate")->add_child_text (raw_convert<string> (_video_frame_rate));
        node->add_child("VideoFrameType")->add_child_text (raw_convert<string> (static_cast<int> (_video_frame_type)));
-       node->add_child("LeftCrop")->add_child_text (raw_convert<string> (_crop.left));
-       node->add_child("RightCrop")->add_child_text (raw_convert<string> (_crop.right));
-       node->add_child("TopCrop")->add_child_text (raw_convert<string> (_crop.top));
-       node->add_child("BottomCrop")->add_child_text (raw_convert<string> (_crop.bottom));
+       _crop.as_xml (node);
        _scale.as_xml (node->add_child("Scale"));
        _colour_conversion.as_xml (node->add_child("ColourConversion"));
 }
index 7af79a417ed193780931e805eda92d5ca1d58515..c0699ad4407158294a3c6d48eccdc8739efdca36 100644 (file)
@@ -1,5 +1,5 @@
 /*
-    Copyright (C) 2012 Carl Hetherington <cth@carlh.net>
+    Copyright (C) 2012-2014 Carl Hetherington <cth@carlh.net>
 
     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
index 6a1e2fa4140d8f2c5bb49693a1c1779312ace9cd..896517b270ae0bfc293f3505d208abb491a213fd 100644 (file)
@@ -50,8 +50,8 @@ static int frame = 0;
 void
 process_video (shared_ptr<PlayerVideoFrame> pvf)
 {
-       shared_ptr<DCPVideoFrame> local  (new DCPVideoFrame (pvf->image(), frame, pvf->eyes(), pvf->colour_conversion(), film->video_frame_rate(), 250000000, RESOLUTION_2K, log_));
-       shared_ptr<DCPVideoFrame> remote (new DCPVideoFrame (pvf->image(), frame, pvf->eyes(), pvf->colour_conversion(), film->video_frame_rate(), 250000000, RESOLUTION_2K, log_));
+       shared_ptr<DCPVideoFrame> local  (new DCPVideoFrame (pvf, frame, film->video_frame_rate(), 250000000, RESOLUTION_2K, log_));
+       shared_ptr<DCPVideoFrame> remote (new DCPVideoFrame (pvf, frame, film->video_frame_rate(), 250000000, RESOLUTION_2K, log_));
 
        cout << "Frame " << frame << ": ";
        cout.flush ();
index 1ad156ae38f98495ce3a23e58e71ce3da6c18369..2b0e96775274d1a231cbb5c10c44f5fc8780016c 100644 (file)
@@ -1,5 +1,5 @@
 /*
-    Copyright (C) 2012 Carl Hetherington <cth@carlh.net>
+    Copyright (C) 2012-2014 Carl Hetherington <cth@carlh.net>
 
     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
@@ -23,6 +23,8 @@
 #include "lib/image.h"
 #include "lib/cross.h"
 #include "lib/dcp_video_frame.h"
+#include "lib/scaler.h"
+#include "lib/player_video_frame.h"
 
 using std::list;
 using boost::shared_ptr;
@@ -67,16 +69,26 @@ BOOST_AUTO_TEST_CASE (client_server_test)
                p += sub_image->stride()[0];
        }
 
-//     shared_ptr<Subtitle> subtitle (new Subtitle (Position<int> (50, 60), sub_image));
+       shared_ptr<PlayerVideoFrame> pvf (
+               new PlayerVideoFrame (
+                       image,
+                       Crop (),
+                       libdcp::Size (1998, 1080),
+                       libdcp::Size (1998, 1080),
+                       Scaler::from_id ("bicubic"),
+                       EYES_BOTH,
+                       ColourConversion ()
+                       )
+               );
+
+       pvf->set_subtitle (sub_image, Position<int> (50, 60));
 
        shared_ptr<FileLog> log (new FileLog ("build/test/client_server_test.log"));
 
        shared_ptr<DCPVideoFrame> frame (
                new DCPVideoFrame (
-                       image,
+                       pvf,
                        0,
-                       EYES_BOTH,
-                       ColourConversion (),
                        24,
                        200000000,
                        RESOLUTION_2K,