From 15f23b356b757a9697bf1a9ec30c243ab8070404 Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Tue, 1 Jul 2014 14:28:04 +0100 Subject: DCPVideoFrame -> DCPVideo and PlayerVideoFrame -> PlayerVideo. --- src/lib/dcp_video.cc | 403 ++++++++++++++++++++++++++++++++++++++ src/lib/dcp_video.h | 127 ++++++++++++ src/lib/dcp_video_frame.cc | 403 -------------------------------------- src/lib/dcp_video_frame.h | 127 ------------ src/lib/encoder.cc | 14 +- src/lib/encoder.h | 8 +- src/lib/player.cc | 24 +-- src/lib/player.h | 6 +- src/lib/player_video.cc | 146 ++++++++++++++ src/lib/player_video.h | 67 +++++++ src/lib/player_video_frame.cc | 146 -------------- src/lib/player_video_frame.h | 67 ------- src/lib/server.cc | 8 +- src/lib/transcoder.cc | 4 +- src/lib/writer.cc | 2 +- src/lib/wscript | 4 +- src/tools/dcpomatic_server_cli.cc | 2 +- src/tools/server_test.cc | 10 +- src/wx/film_viewer.cc | 4 +- src/wx/film_viewer.h | 2 +- 20 files changed, 787 insertions(+), 787 deletions(-) create mode 100644 src/lib/dcp_video.cc create mode 100644 src/lib/dcp_video.h delete mode 100644 src/lib/dcp_video_frame.cc delete mode 100644 src/lib/dcp_video_frame.h create mode 100644 src/lib/player_video.cc create mode 100644 src/lib/player_video.h delete mode 100644 src/lib/player_video_frame.cc delete mode 100644 src/lib/player_video_frame.h (limited to 'src') diff --git a/src/lib/dcp_video.cc b/src/lib/dcp_video.cc new file mode 100644 index 000000000..8d4a5925f --- /dev/null +++ b/src/lib/dcp_video.cc @@ -0,0 +1,403 @@ +/* + Copyright (C) 2012-2014 Carl Hetherington + Taken from code Copyright (C) 2010-2011 Terrence Meiczinger + + 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. + +*/ + +/** @file src/dcp_video_frame.cc + * @brief A single frame of video destined for a DCP. + * + * Given an Image and some settings, this class knows how to encode + * the image to J2K either on the local host or on a remote server. + * + * Objects of this class are used for the queue that we keep + * of images that require encoding. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "film.h" +#include "dcp_video.h" +#include "config.h" +#include "exceptions.h" +#include "server.h" +#include "util.h" +#include "scaler.h" +#include "image.h" +#include "log.h" +#include "cross.h" +#include "player_video.h" + +#define LOG_GENERAL(...) _log->log (String::compose (__VA_ARGS__), Log::TYPE_GENERAL); + +#include "i18n.h" + +using std::string; +using std::stringstream; +using std::cout; +using boost::shared_ptr; +using boost::lexical_cast; +using dcp::Size; +using dcp::raw_convert; + +#define DCI_COEFFICENT (48.0 / 52.37) + +/** Construct a DCP video frame. + * @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. + */ +DCPVideo::DCPVideo ( + shared_ptr frame, int index, int dcp_fps, int bw, Resolution r, shared_ptr l + ) + : _frame (frame) + , _index (index) + , _frames_per_second (dcp_fps) + , _j2k_bandwidth (bw) + , _resolution (r) + , _log (l) +{ + +} + +DCPVideo::DCPVideo (shared_ptr frame, shared_ptr node, shared_ptr log) + : _frame (frame) + , _log (log) +{ + _index = node->number_child ("Index"); + _frames_per_second = node->number_child ("FramesPerSecond"); + _j2k_bandwidth = node->number_child ("J2KBandwidth"); + _resolution = Resolution (node->optional_number_child("Resolution").get_value_or (RESOLUTION_2K)); +} + +/** J2K-encode this frame on the local host. + * @return Encoded data. + */ +shared_ptr +DCPVideo::encode_locally () +{ + shared_ptr in_lut = dcp::GammaLUT::cache.get ( + 12, _frame->colour_conversion().input_gamma, _frame->colour_conversion().input_gamma_linearised + ); + + /* XXX: libdcp should probably use boost */ + + double matrix[3][3]; + for (int i = 0; i < 3; ++i) { + for (int j = 0; j < 3; ++j) { + matrix[i][j] = _frame->colour_conversion().matrix (i, j); + } + } + + shared_ptr xyz = dcp::rgb_to_xyz ( + _frame->image(), + in_lut, + dcp::GammaLUT::cache.get (16, 1 / _frame->colour_conversion().output_gamma, false), + matrix + ); + + /* Set the max image and component sizes based on frame_rate */ + int max_cs_len = ((float) _j2k_bandwidth) / 8 / _frames_per_second; + if (_frame->eyes() == EYES_LEFT || _frame->eyes() == EYES_RIGHT) { + /* In 3D we have only half the normal bandwidth per eye */ + max_cs_len /= 2; + } + int const max_comp_size = max_cs_len / 1.25; + + /* get a J2K compressor handle */ + opj_cinfo_t* cinfo = opj_create_compress (CODEC_J2K); + if (cinfo == 0) { + throw EncodeError (N_("could not create JPEG2000 encoder")); + } + + /* Set encoding parameters to default values */ + opj_cparameters_t parameters; + opj_set_default_encoder_parameters (¶meters); + + /* Set default cinema parameters */ + parameters.tile_size_on = false; + parameters.cp_tdx = 1; + parameters.cp_tdy = 1; + + /* Tile part */ + parameters.tp_flag = 'C'; + parameters.tp_on = 1; + + /* Tile and Image shall be at (0,0) */ + parameters.cp_tx0 = 0; + parameters.cp_ty0 = 0; + parameters.image_offset_x0 = 0; + parameters.image_offset_y0 = 0; + + /* Codeblock size = 32x32 */ + parameters.cblockw_init = 32; + parameters.cblockh_init = 32; + parameters.csty |= 0x01; + + /* The progression order shall be CPRL */ + parameters.prog_order = CPRL; + + /* No ROI */ + parameters.roi_compno = -1; + + parameters.subsampling_dx = 1; + parameters.subsampling_dy = 1; + + /* 9-7 transform */ + parameters.irreversible = 1; + + parameters.tcp_rates[0] = 0; + parameters.tcp_numlayers++; + parameters.cp_disto_alloc = 1; + parameters.cp_rsiz = _resolution == RESOLUTION_2K ? CINEMA2K : CINEMA4K; + if (_resolution == RESOLUTION_4K) { + parameters.numpocs = 2; + parameters.POC[0].tile = 1; + parameters.POC[0].resno0 = 0; + parameters.POC[0].compno0 = 0; + parameters.POC[0].layno1 = 1; + parameters.POC[0].resno1 = parameters.numresolution - 1; + parameters.POC[0].compno1 = 3; + parameters.POC[0].prg1 = CPRL; + parameters.POC[1].tile = 1; + parameters.POC[1].resno0 = parameters.numresolution - 1; + parameters.POC[1].compno0 = 0; + parameters.POC[1].layno1 = 1; + parameters.POC[1].resno1 = parameters.numresolution; + parameters.POC[1].compno1 = 3; + parameters.POC[1].prg1 = CPRL; + } + + parameters.cp_comment = strdup (N_("DCP-o-matic")); + parameters.cp_cinema = _resolution == RESOLUTION_2K ? CINEMA2K_24 : CINEMA4K_24; + + /* 3 components, so use MCT */ + parameters.tcp_mct = 1; + + /* set max image */ + parameters.max_comp_size = max_comp_size; + parameters.tcp_rates[0] = ((float) (3 * xyz->size().width * xyz->size().height * 12)) / (max_cs_len * 8); + + /* Set event manager to null (openjpeg 1.3 bug) */ + cinfo->event_mgr = 0; + + /* Setup the encoder parameters using the current image and user parameters */ + opj_setup_encoder (cinfo, ¶meters, xyz->opj_image ()); + + opj_cio_t* cio = opj_cio_open ((opj_common_ptr) cinfo, 0, 0); + if (cio == 0) { + opj_destroy_compress (cinfo); + throw EncodeError (N_("could not open JPEG2000 stream")); + } + + int const r = opj_encode (cinfo, cio, xyz->opj_image(), 0); + if (r == 0) { + opj_cio_close (cio); + opj_destroy_compress (cinfo); + throw EncodeError (N_("JPEG2000 encoding failed")); + } + + switch (_frame->eyes()) { + case EYES_BOTH: + LOG_GENERAL (N_("Finished locally-encoded frame %1 for mono"), _index); + break; + case EYES_LEFT: + LOG_GENERAL (N_("Finished locally-encoded frame %1 for L"), _index); + break; + case EYES_RIGHT: + LOG_GENERAL (N_("Finished locally-encoded frame %1 for R"), _index); + break; + default: + break; + } + + shared_ptr enc (new LocallyEncodedData (cio->buffer, cio_tell (cio))); + + opj_cio_close (cio); + free (parameters.cp_comment); + opj_destroy_compress (cinfo); + + return enc; +} + +/** Send this frame to a remote server for J2K encoding, then read the result. + * @param serv Server to send to. + * @return Encoded data. + */ +shared_ptr +DCPVideo::encode_remotely (ServerDescription serv) +{ + 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 (Config::instance()->server_port_base ())); + boost::asio::ip::tcp::resolver::iterator endpoint_iterator = resolver.resolve (query); + + shared_ptr socket (new Socket); + + 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 (SERVER_LINK_VERSION)); + add_metadata (root); + + LOG_GENERAL (N_("Sending frame %1 to remote"), _index); + + /* Send XML metadata */ + stringstream xml; + doc.write_to_stream (xml, "UTF-8"); + socket->write (xml.str().length() + 1); + socket->write ((uint8_t *) xml.str().c_str(), xml.str().length() + 1); + + /* 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 e (new RemotelyEncodedData (socket->read_uint32 ())); + socket->read (e->data(), e->size()); + + LOG_GENERAL (N_("Finished remotely-encoded frame %1"), _index); + + return e; +} + +void +DCPVideo::add_metadata (xmlpp::Element* el) const +{ + el->add_child("Index")->add_child_text (raw_convert (_index)); + el->add_child("FramesPerSecond")->add_child_text (raw_convert (_frames_per_second)); + el->add_child("J2KBandwidth")->add_child_text (raw_convert (_j2k_bandwidth)); + el->add_child("Resolution")->add_child_text (raw_convert (int (_resolution))); + _frame->add_metadata (el); +} + +Eyes +DCPVideo::eyes () const +{ + return _frame->eyes (); +} + +EncodedData::EncodedData (int s) + : _data (new uint8_t[s]) + , _size (s) +{ + +} + +EncodedData::EncodedData (boost::filesystem::path file) +{ + _size = boost::filesystem::file_size (file); + _data = new uint8_t[_size]; + + FILE* f = fopen_boost (file, "rb"); + if (!f) { + throw FileError (_("could not open file for reading"), file); + } + + size_t const r = fread (_data, 1, _size, f); + if (r != size_t (_size)) { + fclose (f); + throw FileError (_("could not read encoded data"), file); + } + + fclose (f); +} + + +EncodedData::~EncodedData () +{ + delete[] _data; +} + +/** Write this data to a J2K file. + * @param Film Film. + * @param frame DCP frame index. + */ +void +EncodedData::write (shared_ptr film, int frame, Eyes eyes) const +{ + boost::filesystem::path const tmp_j2c = film->j2c_path (frame, eyes, true); + + FILE* f = fopen_boost (tmp_j2c, "wb"); + + if (!f) { + throw WriteFileError (tmp_j2c, errno); + } + + fwrite (_data, 1, _size, f); + fclose (f); + + boost::filesystem::path const real_j2c = film->j2c_path (frame, eyes, false); + + /* Rename the file from foo.j2c.tmp to foo.j2c now that it is complete */ + boost::filesystem::rename (tmp_j2c, real_j2c); +} + +void +EncodedData::write_info (shared_ptr film, int frame, Eyes eyes, dcp::FrameInfo fin) const +{ + boost::filesystem::path const info = film->info_path (frame, eyes); + FILE* h = fopen_boost (info, "w"); + fin.write (h); + fclose (h); +} + +/** Send this data to a socket. + * @param socket Socket + */ +void +EncodedData::send (shared_ptr socket) +{ + socket->write (_size); + socket->write (_data, _size); +} + +LocallyEncodedData::LocallyEncodedData (uint8_t* d, int s) + : EncodedData (s) +{ + memcpy (_data, d, s); +} + +/** @param s Size of data in bytes */ +RemotelyEncodedData::RemotelyEncodedData (int s) + : EncodedData (s) +{ + +} diff --git a/src/lib/dcp_video.h b/src/lib/dcp_video.h new file mode 100644 index 000000000..7b01966bd --- /dev/null +++ b/src/lib/dcp_video.h @@ -0,0 +1,127 @@ +/* + Copyright (C) 2012-2014 Carl Hetherington + Taken from code Copyright (C) 2010-2011 Terrence Meiczinger + + 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 "util.h" + +/** @file src/dcp_video_frame.h + * @brief A single frame of video destined for a DCP. + */ + +class Film; +class ServerDescription; +class Scaler; +class Image; +class Log; +class Subtitle; +class PlayerVideo; + +/** @class EncodedData + * @brief Container for J2K-encoded data. + */ +class EncodedData : public boost::noncopyable +{ +public: + /** @param s Size of data, in bytes */ + EncodedData (int s); + + EncodedData (boost::filesystem::path); + + virtual ~EncodedData (); + + void send (boost::shared_ptr socket); + void write (boost::shared_ptr, int, Eyes) const; + void write_info (boost::shared_ptr, int, Eyes, dcp::FrameInfo) const; + + /** @return data */ + uint8_t* data () const { + return _data; + } + + /** @return data size, in bytes */ + int size () const { + return _size; + } + +protected: + uint8_t* _data; ///< data + int _size; ///< data size in bytes +}; + +/** @class LocallyEncodedData + * @brief EncodedData that was encoded locally; this class + * just keeps a pointer to the data, but does no memory + * management. + */ +class LocallyEncodedData : public EncodedData +{ +public: + /** @param d Data (which will be copied by this class) + * @param s Size of data, in bytes. + */ + LocallyEncodedData (uint8_t* d, int s); +}; + +/** @class RemotelyEncodedData + * @brief EncodedData that is being read from a remote server; + * this class allocates and manages memory for the data. + */ +class RemotelyEncodedData : public EncodedData +{ +public: + RemotelyEncodedData (int s); +}; + +/** @class DCPVideo + * @brief A single frame of video destined for a DCP. + * + * Given an Image and some settings, this class knows how to encode + * the image to J2K either on the local host or on a remote server. + * + * Objects of this class are used for the queue that we keep + * of images that require encoding. + */ +class DCPVideo : public boost::noncopyable +{ +public: + DCPVideo (boost::shared_ptr, int, int, int, Resolution, boost::shared_ptr); + DCPVideo (boost::shared_ptr, cxml::ConstNodePtr, boost::shared_ptr); + + boost::shared_ptr encode_locally (); + boost::shared_ptr encode_remotely (ServerDescription); + + int index () const { + return _index; + } + + Eyes eyes () const; + +private: + + void add_metadata (xmlpp::Element *) const; + + boost::shared_ptr _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) + + boost::shared_ptr _log; ///< log +}; diff --git a/src/lib/dcp_video_frame.cc b/src/lib/dcp_video_frame.cc deleted file mode 100644 index 4054f05cd..000000000 --- a/src/lib/dcp_video_frame.cc +++ /dev/null @@ -1,403 +0,0 @@ -/* - Copyright (C) 2012-2014 Carl Hetherington - Taken from code Copyright (C) 2010-2011 Terrence Meiczinger - - 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. - -*/ - -/** @file src/dcp_video_frame.cc - * @brief A single frame of video destined for a DCP. - * - * Given an Image and some settings, this class knows how to encode - * the image to J2K either on the local host or on a remote server. - * - * Objects of this class are used for the queue that we keep - * of images that require encoding. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "film.h" -#include "dcp_video_frame.h" -#include "config.h" -#include "exceptions.h" -#include "server.h" -#include "util.h" -#include "scaler.h" -#include "image.h" -#include "log.h" -#include "cross.h" -#include "player_video_frame.h" - -#define LOG_GENERAL(...) _log->log (String::compose (__VA_ARGS__), Log::TYPE_GENERAL); - -#include "i18n.h" - -using std::string; -using std::stringstream; -using std::cout; -using boost::shared_ptr; -using boost::lexical_cast; -using dcp::Size; -using dcp::raw_convert; - -#define DCI_COEFFICENT (48.0 / 52.37) - -/** Construct a DCP video frame. - * @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 frame, int index, int dcp_fps, int bw, Resolution r, shared_ptr l - ) - : _frame (frame) - , _index (index) - , _frames_per_second (dcp_fps) - , _j2k_bandwidth (bw) - , _resolution (r) - , _log (l) -{ - -} - -DCPVideoFrame::DCPVideoFrame (shared_ptr frame, shared_ptr node, shared_ptr log) - : _frame (frame) - , _log (log) -{ - _index = node->number_child ("Index"); - _frames_per_second = node->number_child ("FramesPerSecond"); - _j2k_bandwidth = node->number_child ("J2KBandwidth"); - _resolution = Resolution (node->optional_number_child("Resolution").get_value_or (RESOLUTION_2K)); -} - -/** J2K-encode this frame on the local host. - * @return Encoded data. - */ -shared_ptr -DCPVideoFrame::encode_locally () -{ - shared_ptr in_lut = dcp::GammaLUT::cache.get ( - 12, _frame->colour_conversion().input_gamma, _frame->colour_conversion().input_gamma_linearised - ); - - /* XXX: libdcp should probably use boost */ - - double matrix[3][3]; - for (int i = 0; i < 3; ++i) { - for (int j = 0; j < 3; ++j) { - matrix[i][j] = _frame->colour_conversion().matrix (i, j); - } - } - - shared_ptr xyz = dcp::rgb_to_xyz ( - _frame->image(), - in_lut, - dcp::GammaLUT::cache.get (16, 1 / _frame->colour_conversion().output_gamma, false), - matrix - ); - - /* Set the max image and component sizes based on frame_rate */ - int max_cs_len = ((float) _j2k_bandwidth) / 8 / _frames_per_second; - if (_frame->eyes() == EYES_LEFT || _frame->eyes() == EYES_RIGHT) { - /* In 3D we have only half the normal bandwidth per eye */ - max_cs_len /= 2; - } - int const max_comp_size = max_cs_len / 1.25; - - /* get a J2K compressor handle */ - opj_cinfo_t* cinfo = opj_create_compress (CODEC_J2K); - if (cinfo == 0) { - throw EncodeError (N_("could not create JPEG2000 encoder")); - } - - /* Set encoding parameters to default values */ - opj_cparameters_t parameters; - opj_set_default_encoder_parameters (¶meters); - - /* Set default cinema parameters */ - parameters.tile_size_on = false; - parameters.cp_tdx = 1; - parameters.cp_tdy = 1; - - /* Tile part */ - parameters.tp_flag = 'C'; - parameters.tp_on = 1; - - /* Tile and Image shall be at (0,0) */ - parameters.cp_tx0 = 0; - parameters.cp_ty0 = 0; - parameters.image_offset_x0 = 0; - parameters.image_offset_y0 = 0; - - /* Codeblock size = 32x32 */ - parameters.cblockw_init = 32; - parameters.cblockh_init = 32; - parameters.csty |= 0x01; - - /* The progression order shall be CPRL */ - parameters.prog_order = CPRL; - - /* No ROI */ - parameters.roi_compno = -1; - - parameters.subsampling_dx = 1; - parameters.subsampling_dy = 1; - - /* 9-7 transform */ - parameters.irreversible = 1; - - parameters.tcp_rates[0] = 0; - parameters.tcp_numlayers++; - parameters.cp_disto_alloc = 1; - parameters.cp_rsiz = _resolution == RESOLUTION_2K ? CINEMA2K : CINEMA4K; - if (_resolution == RESOLUTION_4K) { - parameters.numpocs = 2; - parameters.POC[0].tile = 1; - parameters.POC[0].resno0 = 0; - parameters.POC[0].compno0 = 0; - parameters.POC[0].layno1 = 1; - parameters.POC[0].resno1 = parameters.numresolution - 1; - parameters.POC[0].compno1 = 3; - parameters.POC[0].prg1 = CPRL; - parameters.POC[1].tile = 1; - parameters.POC[1].resno0 = parameters.numresolution - 1; - parameters.POC[1].compno0 = 0; - parameters.POC[1].layno1 = 1; - parameters.POC[1].resno1 = parameters.numresolution; - parameters.POC[1].compno1 = 3; - parameters.POC[1].prg1 = CPRL; - } - - parameters.cp_comment = strdup (N_("DCP-o-matic")); - parameters.cp_cinema = _resolution == RESOLUTION_2K ? CINEMA2K_24 : CINEMA4K_24; - - /* 3 components, so use MCT */ - parameters.tcp_mct = 1; - - /* set max image */ - parameters.max_comp_size = max_comp_size; - parameters.tcp_rates[0] = ((float) (3 * xyz->size().width * xyz->size().height * 12)) / (max_cs_len * 8); - - /* Set event manager to null (openjpeg 1.3 bug) */ - cinfo->event_mgr = 0; - - /* Setup the encoder parameters using the current image and user parameters */ - opj_setup_encoder (cinfo, ¶meters, xyz->opj_image ()); - - opj_cio_t* cio = opj_cio_open ((opj_common_ptr) cinfo, 0, 0); - if (cio == 0) { - opj_destroy_compress (cinfo); - throw EncodeError (N_("could not open JPEG2000 stream")); - } - - int const r = opj_encode (cinfo, cio, xyz->opj_image(), 0); - if (r == 0) { - opj_cio_close (cio); - opj_destroy_compress (cinfo); - throw EncodeError (N_("JPEG2000 encoding failed")); - } - - switch (_frame->eyes()) { - case EYES_BOTH: - LOG_GENERAL (N_("Finished locally-encoded frame %1 for mono"), _index); - break; - case EYES_LEFT: - LOG_GENERAL (N_("Finished locally-encoded frame %1 for L"), _index); - break; - case EYES_RIGHT: - LOG_GENERAL (N_("Finished locally-encoded frame %1 for R"), _index); - break; - default: - break; - } - - shared_ptr enc (new LocallyEncodedData (cio->buffer, cio_tell (cio))); - - opj_cio_close (cio); - free (parameters.cp_comment); - opj_destroy_compress (cinfo); - - return enc; -} - -/** Send this frame to a remote server for J2K encoding, then read the result. - * @param serv Server to send to. - * @return Encoded data. - */ -shared_ptr -DCPVideoFrame::encode_remotely (ServerDescription serv) -{ - 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 (Config::instance()->server_port_base ())); - boost::asio::ip::tcp::resolver::iterator endpoint_iterator = resolver.resolve (query); - - shared_ptr socket (new Socket); - - 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 (SERVER_LINK_VERSION)); - add_metadata (root); - - LOG_GENERAL (N_("Sending frame %1 to remote"), _index); - - /* Send XML metadata */ - stringstream xml; - doc.write_to_stream (xml, "UTF-8"); - socket->write (xml.str().length() + 1); - socket->write ((uint8_t *) xml.str().c_str(), xml.str().length() + 1); - - /* 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 e (new RemotelyEncodedData (socket->read_uint32 ())); - socket->read (e->data(), e->size()); - - LOG_GENERAL (N_("Finished remotely-encoded frame %1"), _index); - - return e; -} - -void -DCPVideoFrame::add_metadata (xmlpp::Element* el) const -{ - el->add_child("Index")->add_child_text (raw_convert (_index)); - el->add_child("FramesPerSecond")->add_child_text (raw_convert (_frames_per_second)); - el->add_child("J2KBandwidth")->add_child_text (raw_convert (_j2k_bandwidth)); - el->add_child("Resolution")->add_child_text (raw_convert (int (_resolution))); - _frame->add_metadata (el); -} - -Eyes -DCPVideoFrame::eyes () const -{ - return _frame->eyes (); -} - -EncodedData::EncodedData (int s) - : _data (new uint8_t[s]) - , _size (s) -{ - -} - -EncodedData::EncodedData (boost::filesystem::path file) -{ - _size = boost::filesystem::file_size (file); - _data = new uint8_t[_size]; - - FILE* f = fopen_boost (file, "rb"); - if (!f) { - throw FileError (_("could not open file for reading"), file); - } - - size_t const r = fread (_data, 1, _size, f); - if (r != size_t (_size)) { - fclose (f); - throw FileError (_("could not read encoded data"), file); - } - - fclose (f); -} - - -EncodedData::~EncodedData () -{ - delete[] _data; -} - -/** Write this data to a J2K file. - * @param Film Film. - * @param frame DCP frame index. - */ -void -EncodedData::write (shared_ptr film, int frame, Eyes eyes) const -{ - boost::filesystem::path const tmp_j2c = film->j2c_path (frame, eyes, true); - - FILE* f = fopen_boost (tmp_j2c, "wb"); - - if (!f) { - throw WriteFileError (tmp_j2c, errno); - } - - fwrite (_data, 1, _size, f); - fclose (f); - - boost::filesystem::path const real_j2c = film->j2c_path (frame, eyes, false); - - /* Rename the file from foo.j2c.tmp to foo.j2c now that it is complete */ - boost::filesystem::rename (tmp_j2c, real_j2c); -} - -void -EncodedData::write_info (shared_ptr film, int frame, Eyes eyes, dcp::FrameInfo fin) const -{ - boost::filesystem::path const info = film->info_path (frame, eyes); - FILE* h = fopen_boost (info, "w"); - fin.write (h); - fclose (h); -} - -/** Send this data to a socket. - * @param socket Socket - */ -void -EncodedData::send (shared_ptr socket) -{ - socket->write (_size); - socket->write (_data, _size); -} - -LocallyEncodedData::LocallyEncodedData (uint8_t* d, int s) - : EncodedData (s) -{ - memcpy (_data, d, s); -} - -/** @param s Size of data in bytes */ -RemotelyEncodedData::RemotelyEncodedData (int s) - : EncodedData (s) -{ - -} diff --git a/src/lib/dcp_video_frame.h b/src/lib/dcp_video_frame.h deleted file mode 100644 index 7393efde6..000000000 --- a/src/lib/dcp_video_frame.h +++ /dev/null @@ -1,127 +0,0 @@ -/* - Copyright (C) 2012-2014 Carl Hetherington - Taken from code Copyright (C) 2010-2011 Terrence Meiczinger - - 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 "util.h" - -/** @file src/dcp_video_frame.h - * @brief A single frame of video destined for a DCP. - */ - -class Film; -class ServerDescription; -class Scaler; -class Image; -class Log; -class Subtitle; -class PlayerVideoFrame; - -/** @class EncodedData - * @brief Container for J2K-encoded data. - */ -class EncodedData : public boost::noncopyable -{ -public: - /** @param s Size of data, in bytes */ - EncodedData (int s); - - EncodedData (boost::filesystem::path); - - virtual ~EncodedData (); - - void send (boost::shared_ptr socket); - void write (boost::shared_ptr, int, Eyes) const; - void write_info (boost::shared_ptr, int, Eyes, dcp::FrameInfo) const; - - /** @return data */ - uint8_t* data () const { - return _data; - } - - /** @return data size, in bytes */ - int size () const { - return _size; - } - -protected: - uint8_t* _data; ///< data - int _size; ///< data size in bytes -}; - -/** @class LocallyEncodedData - * @brief EncodedData that was encoded locally; this class - * just keeps a pointer to the data, but does no memory - * management. - */ -class LocallyEncodedData : public EncodedData -{ -public: - /** @param d Data (which will be copied by this class) - * @param s Size of data, in bytes. - */ - LocallyEncodedData (uint8_t* d, int s); -}; - -/** @class RemotelyEncodedData - * @brief EncodedData that is being read from a remote server; - * this class allocates and manages memory for the data. - */ -class RemotelyEncodedData : public EncodedData -{ -public: - RemotelyEncodedData (int s); -}; - -/** @class DCPVideoFrame - * @brief A single frame of video destined for a DCP. - * - * Given an Image and some settings, this class knows how to encode - * the image to J2K either on the local host or on a remote server. - * - * Objects of this class are used for the queue that we keep - * of images that require encoding. - */ -class DCPVideoFrame : public boost::noncopyable -{ -public: - DCPVideoFrame (boost::shared_ptr, int, int, int, Resolution, boost::shared_ptr); - DCPVideoFrame (boost::shared_ptr, cxml::ConstNodePtr, boost::shared_ptr); - - boost::shared_ptr encode_locally (); - boost::shared_ptr encode_remotely (ServerDescription); - - int index () const { - return _index; - } - - Eyes eyes () const; - -private: - - void add_metadata (xmlpp::Element *) const; - - boost::shared_ptr _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) - - boost::shared_ptr _log; ///< log -}; diff --git a/src/lib/encoder.cc b/src/lib/encoder.cc index 0756586a9..2b1f1d9b3 100644 --- a/src/lib/encoder.cc +++ b/src/lib/encoder.cc @@ -29,13 +29,13 @@ #include "film.h" #include "log.h" #include "config.h" -#include "dcp_video_frame.h" +#include "dcp_video.h" #include "server.h" #include "cross.h" #include "writer.h" #include "server_finder.h" #include "player.h" -#include "player_video_frame.h" +#include "player_video.h" #include "i18n.h" @@ -125,7 +125,7 @@ Encoder::process_end () So just mop up anything left in the queue here. */ - for (list >::iterator i = _queue.begin(); i != _queue.end(); ++i) { + for (list >::iterator i = _queue.begin(); i != _queue.end(); ++i) { LOG_GENERAL (N_("Encode left-over frame %1"), (*i)->index ()); try { _writer->write ((*i)->encode_locally(), (*i)->index (), (*i)->eyes ()); @@ -181,7 +181,7 @@ Encoder::frame_done () } void -Encoder::process_video (shared_ptr pvf) +Encoder::process_video (shared_ptr pvf) { _waker.nudge (); @@ -213,8 +213,8 @@ Encoder::process_video (shared_ptr pvf) } else { /* Queue this new frame for encoding */ LOG_TIMING ("adding to queue of %1", _queue.size ()); - _queue.push_back (shared_ptr ( - new DCPVideoFrame ( + _queue.push_back (shared_ptr ( + new DCPVideo ( pvf, _video_frames_out, _film->video_frame_rate(), @@ -284,7 +284,7 @@ try } LOG_TIMING ("[%1] encoder thread wakes with queue of %2", boost::this_thread::get_id(), _queue.size()); - shared_ptr vf = _queue.front (); + shared_ptr vf = _queue.front (); LOG_TIMING ("[%1] encoder thread pops frame %2 (%3) from queue", boost::this_thread::get_id(), vf->index(), vf->eyes ()); _queue.pop_front (); diff --git a/src/lib/encoder.h b/src/lib/encoder.h index 6bb97012a..4502b7151 100644 --- a/src/lib/encoder.h +++ b/src/lib/encoder.h @@ -44,12 +44,12 @@ class Image; class AudioBuffers; class Film; class ServerDescription; -class DCPVideoFrame; +class DCPVideo; class EncodedData; class Writer; class Job; class ServerFinder; -class PlayerVideoFrame; +class PlayerVideo; /** @class Encoder * @brief Encoder to J2K and WAV for DCP. @@ -70,7 +70,7 @@ public: /** Call with a frame of video. * @param f Video frame. */ - void process_video (boost::shared_ptr f); + void process_video (boost::shared_ptr f); /** Call with some audio data */ void process_audio (boost::shared_ptr); @@ -107,7 +107,7 @@ private: int _video_frames_out; bool _terminate; - std::list > _queue; + std::list > _queue; std::list _threads; mutable boost::mutex _mutex; /** condition to manage thread wakeups when we have nothing to do */ diff --git a/src/lib/player.cc b/src/lib/player.cc index 380133b61..b634028ba 100644 --- a/src/lib/player.cc +++ b/src/lib/player.cc @@ -41,7 +41,7 @@ #include "render_subtitles.h" #include "config.h" #include "content_video.h" -#include "player_video_frame.h" +#include "player_video.h" #include "frame_rate_change.h" #define LOG_GENERAL(...) _film->log()->log (String::compose (__VA_ARGS__), Log::TYPE_GENERAL); @@ -292,11 +292,11 @@ Player::set_approximate_size () _approximate_size = true; } -shared_ptr +shared_ptr Player::black_player_video_frame () const { - return shared_ptr ( - new PlayerVideoFrame ( + return shared_ptr ( + new PlayerVideo ( shared_ptr (new RawImageProxy (_black_image, _film->log ())), Crop (), _video_container_size, @@ -309,8 +309,8 @@ Player::black_player_video_frame () const ); } -/** @return All PlayerVideoFrames at the given time (there may be two frames for 3D) */ -list > +/** @return All PlayerVideos at the given time (there may be two frames for 3D) */ +list > Player::get_video (DCPTime time, bool accurate) { if (!_have_valid_pieces) { @@ -322,13 +322,13 @@ Player::get_video (DCPTime time, bool accurate) time + DCPTime::from_frames (1, _film->video_frame_rate ()) ); - list > pvf; + list > pvf; if (ov.empty ()) { /* No video content at this time */ pvf.push_back (black_player_video_frame ()); } else { - /* Create a PlayerVideoFrame from the content's video at this time */ + /* Create a PlayerVideo from the content's video at this time */ shared_ptr piece = ov.back (); shared_ptr decoder = dynamic_pointer_cast (piece->decoder); @@ -350,8 +350,8 @@ Player::get_video (DCPTime time, bool accurate) for (list::const_iterator i = content_video.begin(); i != content_video.end(); ++i) { pvf.push_back ( - shared_ptr ( - new PlayerVideoFrame ( + shared_ptr ( + new PlayerVideo ( i->image, content->crop (), image_size, @@ -366,7 +366,7 @@ Player::get_video (DCPTime time, bool accurate) } } - /* Add subtitles to whatever PlayerVideoFrames we got */ + /* Add subtitles to whatever PlayerVideos we got */ list > subs = overlaps ( time, @@ -404,7 +404,7 @@ Player::get_video (DCPTime time, bool accurate) } if (!sub_images.empty ()) { - for (list >::const_iterator i = pvf.begin(); i != pvf.end(); ++i) { + for (list >::const_iterator i = pvf.begin(); i != pvf.end(); ++i) { (*i)->set_subtitle (merge (sub_images)); } } diff --git a/src/lib/player.h b/src/lib/player.h index 6805dc8c7..04503c27a 100644 --- a/src/lib/player.h +++ b/src/lib/player.h @@ -42,7 +42,7 @@ class Piece; class Image; class Decoder; class Resampler; -class PlayerVideoFrame; +class PlayerVideo; class ImageProxy; class PlayerStatistics @@ -85,7 +85,7 @@ class Player : public boost::enable_shared_from_this, public boost::nonc public: Player (boost::shared_ptr, boost::shared_ptr); - std::list > get_video (DCPTime time, bool accurate); + std::list > get_video (DCPTime time, bool accurate); boost::shared_ptr get_audio (DCPTime time, DCPTime length, bool accurate); void set_video_container_size (dcp::Size); @@ -119,7 +119,7 @@ private: VideoFrame dcp_to_content_video (boost::shared_ptr piece, DCPTime t) const; AudioFrame dcp_to_content_audio (boost::shared_ptr piece, DCPTime t) const; ContentTime dcp_to_content_subtitle (boost::shared_ptr piece, DCPTime t) const; - boost::shared_ptr black_player_video_frame () const; + boost::shared_ptr black_player_video_frame () const; /** @return Pieces of content type C that overlap a specified time range in the DCP */ template diff --git a/src/lib/player_video.cc b/src/lib/player_video.cc new file mode 100644 index 000000000..f8e4a3e66 --- /dev/null +++ b/src/lib/player_video.cc @@ -0,0 +1,146 @@ +/* + Copyright (C) 2013-2014 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 "player_video.h" +#include "image.h" +#include "image_proxy.h" +#include "scaler.h" + +using std::string; +using std::cout; +using boost::shared_ptr; +using dcp::raw_convert; + +PlayerVideo::PlayerVideo ( + shared_ptr in, + Crop crop, + dcp::Size inter_size, + dcp::Size out_size, + Scaler const * scaler, + Eyes eyes, + Part part, + ColourConversion colour_conversion + ) + : _in (in) + , _crop (crop) + , _inter_size (inter_size) + , _out_size (out_size) + , _scaler (scaler) + , _eyes (eyes) + , _part (part) + , _colour_conversion (colour_conversion) +{ + +} + +PlayerVideo::PlayerVideo (shared_ptr node, shared_ptr socket, shared_ptr log) +{ + _crop = Crop (node); + + _inter_size = dcp::Size (node->number_child ("InterWidth"), node->number_child ("InterHeight")); + _out_size = dcp::Size (node->number_child ("OutWidth"), node->number_child ("OutHeight")); + _scaler = Scaler::from_id (node->string_child ("Scaler")); + _eyes = (Eyes) node->number_child ("Eyes"); + _part = (Part) node->number_child ("Part"); + _colour_conversion = ColourConversion (node); + + _in = image_proxy_factory (node->node_child ("In"), socket, log); + + if (node->optional_number_child ("SubtitleX")) { + + _subtitle.position = Position (node->number_child ("SubtitleX"), node->number_child ("SubtitleY")); + + _subtitle.image.reset ( + new Image (PIX_FMT_RGBA, dcp::Size (node->number_child ("SubtitleWidth"), node->number_child ("SubtitleHeight")), true) + ); + + _subtitle.image->read_from_socket (socket); + } +} + +void +PlayerVideo::set_subtitle (PositionImage image) +{ + _subtitle = image; +} + +shared_ptr +PlayerVideo::image () const +{ + shared_ptr im = _in->image (); + + Crop total_crop = _crop; + switch (_part) { + case PART_LEFT_HALF: + total_crop.right += im->size().width / 2; + break; + case PART_RIGHT_HALF: + total_crop.left += im->size().width / 2; + break; + case PART_TOP_HALF: + total_crop.bottom += im->size().height / 2; + break; + case PART_BOTTOM_HALF: + total_crop.top += im->size().height / 2; + break; + default: + break; + } + + shared_ptr out = im->crop_scale_window (total_crop, _inter_size, _out_size, _scaler, PIX_FMT_RGB24, true); + + Position const container_offset ((_out_size.width - _inter_size.width) / 2, (_out_size.height - _inter_size.width) / 2); + + if (_subtitle.image) { + out->alpha_blend (_subtitle.image, _subtitle.position); + } + + return out; +} + +void +PlayerVideo::add_metadata (xmlpp::Node* node) const +{ + _crop.as_xml (node); + _in->add_metadata (node->add_child ("In")); + node->add_child("InterWidth")->add_child_text (raw_convert (_inter_size.width)); + node->add_child("InterHeight")->add_child_text (raw_convert (_inter_size.height)); + node->add_child("OutWidth")->add_child_text (raw_convert (_out_size.width)); + node->add_child("OutHeight")->add_child_text (raw_convert (_out_size.height)); + node->add_child("Scaler")->add_child_text (_scaler->id ()); + node->add_child("Eyes")->add_child_text (raw_convert (_eyes)); + node->add_child("Part")->add_child_text (raw_convert (_part)); + _colour_conversion.as_xml (node); + if (_subtitle.image) { + node->add_child ("SubtitleWidth")->add_child_text (raw_convert (_subtitle.image->size().width)); + node->add_child ("SubtitleHeight")->add_child_text (raw_convert (_subtitle.image->size().height)); + node->add_child ("SubtitleX")->add_child_text (raw_convert (_subtitle.position.x)); + node->add_child ("SubtitleY")->add_child_text (raw_convert (_subtitle.position.y)); + } +} + +void +PlayerVideo::send_binary (shared_ptr socket) const +{ + _in->send_binary (socket); + if (_subtitle.image) { + _subtitle.image->write_to_socket (socket); + } +} diff --git a/src/lib/player_video.h b/src/lib/player_video.h new file mode 100644 index 000000000..73557bbfd --- /dev/null +++ b/src/lib/player_video.h @@ -0,0 +1,67 @@ +/* + Copyright (C) 2013-2014 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 "types.h" +#include "position.h" +#include "colour_conversion.h" +#include "position_image.h" + +class Image; +class ImageProxy; +class Scaler; +class Socket; +class Log; + +/** 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, + * or maybe not even bother to combine them at all. + */ +class PlayerVideo +{ +public: + PlayerVideo (boost::shared_ptr, Crop, dcp::Size, dcp::Size, Scaler const *, Eyes, Part, ColourConversion); + PlayerVideo (boost::shared_ptr, boost::shared_ptr, boost::shared_ptr); + + void set_subtitle (PositionImage); + + boost::shared_ptr image () const; + + void add_metadata (xmlpp::Node* node) const; + void send_binary (boost::shared_ptr socket) const; + + Eyes eyes () const { + return _eyes; + } + + ColourConversion colour_conversion () const { + return _colour_conversion; + } + +private: + boost::shared_ptr _in; + Crop _crop; + dcp::Size _inter_size; + dcp::Size _out_size; + Scaler const * _scaler; + Eyes _eyes; + Part _part; + ColourConversion _colour_conversion; + PositionImage _subtitle; +}; diff --git a/src/lib/player_video_frame.cc b/src/lib/player_video_frame.cc deleted file mode 100644 index 5463925bf..000000000 --- a/src/lib/player_video_frame.cc +++ /dev/null @@ -1,146 +0,0 @@ -/* - Copyright (C) 2013-2014 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 "player_video_frame.h" -#include "image.h" -#include "image_proxy.h" -#include "scaler.h" - -using std::string; -using std::cout; -using boost::shared_ptr; -using dcp::raw_convert; - -PlayerVideoFrame::PlayerVideoFrame ( - shared_ptr in, - Crop crop, - dcp::Size inter_size, - dcp::Size out_size, - Scaler const * scaler, - Eyes eyes, - Part part, - ColourConversion colour_conversion - ) - : _in (in) - , _crop (crop) - , _inter_size (inter_size) - , _out_size (out_size) - , _scaler (scaler) - , _eyes (eyes) - , _part (part) - , _colour_conversion (colour_conversion) -{ - -} - -PlayerVideoFrame::PlayerVideoFrame (shared_ptr node, shared_ptr socket, shared_ptr log) -{ - _crop = Crop (node); - - _inter_size = dcp::Size (node->number_child ("InterWidth"), node->number_child ("InterHeight")); - _out_size = dcp::Size (node->number_child ("OutWidth"), node->number_child ("OutHeight")); - _scaler = Scaler::from_id (node->string_child ("Scaler")); - _eyes = (Eyes) node->number_child ("Eyes"); - _part = (Part) node->number_child ("Part"); - _colour_conversion = ColourConversion (node); - - _in = image_proxy_factory (node->node_child ("In"), socket, log); - - if (node->optional_number_child ("SubtitleX")) { - - _subtitle.position = Position (node->number_child ("SubtitleX"), node->number_child ("SubtitleY")); - - _subtitle.image.reset ( - new Image (PIX_FMT_RGBA, dcp::Size (node->number_child ("SubtitleWidth"), node->number_child ("SubtitleHeight")), true) - ); - - _subtitle.image->read_from_socket (socket); - } -} - -void -PlayerVideoFrame::set_subtitle (PositionImage image) -{ - _subtitle = image; -} - -shared_ptr -PlayerVideoFrame::image () const -{ - shared_ptr im = _in->image (); - - Crop total_crop = _crop; - switch (_part) { - case PART_LEFT_HALF: - total_crop.right += im->size().width / 2; - break; - case PART_RIGHT_HALF: - total_crop.left += im->size().width / 2; - break; - case PART_TOP_HALF: - total_crop.bottom += im->size().height / 2; - break; - case PART_BOTTOM_HALF: - total_crop.top += im->size().height / 2; - break; - default: - break; - } - - shared_ptr out = im->crop_scale_window (total_crop, _inter_size, _out_size, _scaler, PIX_FMT_RGB24, true); - - Position const container_offset ((_out_size.width - _inter_size.width) / 2, (_out_size.height - _inter_size.width) / 2); - - if (_subtitle.image) { - out->alpha_blend (_subtitle.image, _subtitle.position); - } - - return out; -} - -void -PlayerVideoFrame::add_metadata (xmlpp::Node* node) const -{ - _crop.as_xml (node); - _in->add_metadata (node->add_child ("In")); - node->add_child("InterWidth")->add_child_text (raw_convert (_inter_size.width)); - node->add_child("InterHeight")->add_child_text (raw_convert (_inter_size.height)); - node->add_child("OutWidth")->add_child_text (raw_convert (_out_size.width)); - node->add_child("OutHeight")->add_child_text (raw_convert (_out_size.height)); - node->add_child("Scaler")->add_child_text (_scaler->id ()); - node->add_child("Eyes")->add_child_text (raw_convert (_eyes)); - node->add_child("Part")->add_child_text (raw_convert (_part)); - _colour_conversion.as_xml (node); - if (_subtitle.image) { - node->add_child ("SubtitleWidth")->add_child_text (raw_convert (_subtitle.image->size().width)); - node->add_child ("SubtitleHeight")->add_child_text (raw_convert (_subtitle.image->size().height)); - node->add_child ("SubtitleX")->add_child_text (raw_convert (_subtitle.position.x)); - node->add_child ("SubtitleY")->add_child_text (raw_convert (_subtitle.position.y)); - } -} - -void -PlayerVideoFrame::send_binary (shared_ptr socket) const -{ - _in->send_binary (socket); - if (_subtitle.image) { - _subtitle.image->write_to_socket (socket); - } -} diff --git a/src/lib/player_video_frame.h b/src/lib/player_video_frame.h deleted file mode 100644 index 4c6a9c630..000000000 --- a/src/lib/player_video_frame.h +++ /dev/null @@ -1,67 +0,0 @@ -/* - Copyright (C) 2013-2014 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 "types.h" -#include "position.h" -#include "colour_conversion.h" -#include "position_image.h" - -class Image; -class ImageProxy; -class Scaler; -class Socket; -class Log; - -/** 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, - * or maybe not even bother to combine them at all. - */ -class PlayerVideoFrame -{ -public: - PlayerVideoFrame (boost::shared_ptr, Crop, dcp::Size, dcp::Size, Scaler const *, Eyes, Part, ColourConversion); - PlayerVideoFrame (boost::shared_ptr, boost::shared_ptr, boost::shared_ptr); - - void set_subtitle (PositionImage); - - boost::shared_ptr image () const; - - void add_metadata (xmlpp::Node* node) const; - void send_binary (boost::shared_ptr socket) const; - - Eyes eyes () const { - return _eyes; - } - - ColourConversion colour_conversion () const { - return _colour_conversion; - } - -private: - boost::shared_ptr _in; - Crop _crop; - dcp::Size _inter_size; - dcp::Size _out_size; - Scaler const * _scaler; - Eyes _eyes; - Part _part; - ColourConversion _colour_conversion; - PositionImage _subtitle; -}; diff --git a/src/lib/server.cc b/src/lib/server.cc index 9d1925de1..2469d4151 100644 --- a/src/lib/server.cc +++ b/src/lib/server.cc @@ -34,10 +34,10 @@ #include "util.h" #include "scaler.h" #include "image.h" -#include "dcp_video_frame.h" +#include "dcp_video.h" #include "config.h" #include "cross.h" -#include "player_video_frame.h" +#include "player_video.h" #include "i18n.h" @@ -112,9 +112,9 @@ Server::process (shared_ptr socket, struct timeval& after_read, struct t return -1; } - shared_ptr pvf (new PlayerVideoFrame (xml, socket, _log)); + shared_ptr pvf (new PlayerVideo (xml, socket, _log)); - DCPVideoFrame dcp_video_frame (pvf, xml, _log); + DCPVideo dcp_video_frame (pvf, xml, _log); gettimeofday (&after_read, 0); diff --git a/src/lib/transcoder.cc b/src/lib/transcoder.cc index a4cd36a4f..1177830be 100644 --- a/src/lib/transcoder.cc +++ b/src/lib/transcoder.cc @@ -61,8 +61,8 @@ Transcoder::go () DCPTime const frame = DCPTime::from_frames (1, _film->video_frame_rate ()); for (DCPTime t; t < _film->length(); t += frame) { - list > v = _player->get_video (t, true); - for (list >::const_iterator i = v.begin(); i != v.end(); ++i) { + list > v = _player->get_video (t, true); + for (list >::const_iterator i = v.begin(); i != v.end(); ++i) { _encoder->process_video (*i); } _encoder->process_audio (_player->get_audio (t, frame, true)); diff --git a/src/lib/writer.cc b/src/lib/writer.cc index 489135b84..ca9b63df4 100644 --- a/src/lib/writer.cc +++ b/src/lib/writer.cc @@ -34,7 +34,7 @@ #include "film.h" #include "ratio.h" #include "log.h" -#include "dcp_video_frame.h" +#include "dcp_video.h" #include "dcp_content_type.h" #include "player.h" #include "audio_mapping.h" diff --git a/src/lib/wscript b/src/lib/wscript index 407d9cde4..1f6a2aa4f 100644 --- a/src/lib/wscript +++ b/src/lib/wscript @@ -16,7 +16,7 @@ sources = """ content_subtitle.cc cross.cc dcp_content_type.cc - dcp_video_frame.cc + dcp_video.cc dcpomatic_time.cc dolby_cp750.cc encoder.cc @@ -48,7 +48,7 @@ sources = """ log.cc md5_digester.cc player.cc - player_video_frame.cc + player_video.cc playlist.cc ratio.cc render_subtitles.cc diff --git a/src/tools/dcpomatic_server_cli.cc b/src/tools/dcpomatic_server_cli.cc index e4ac85f4c..c74e258e8 100644 --- a/src/tools/dcpomatic_server_cli.cc +++ b/src/tools/dcpomatic_server_cli.cc @@ -33,7 +33,7 @@ #include #include #include "lib/config.h" -#include "lib/dcp_video_frame.h" +#include "lib/dcp_video.h" #include "lib/exceptions.h" #include "lib/util.h" #include "lib/config.h" diff --git a/src/tools/server_test.cc b/src/tools/server_test.cc index 5997caab6..acafa4a81 100644 --- a/src/tools/server_test.cc +++ b/src/tools/server_test.cc @@ -27,14 +27,14 @@ #include "lib/util.h" #include "lib/scaler.h" #include "lib/server.h" -#include "lib/dcp_video_frame.h" +#include "lib/dcp_video.h" #include "lib/decoder.h" #include "lib/exceptions.h" #include "lib/scaler.h" #include "lib/log.h" #include "lib/video_decoder.h" #include "lib/player.h" -#include "lib/player_video_frame.h" +#include "lib/player_video.h" using std::cout; using std::cerr; @@ -48,10 +48,10 @@ static shared_ptr log_ (new FileLog ("servomatictest.log")); static int frame_count = 0; void -process_video (shared_ptr pvf) +process_video (shared_ptr pvf) { - shared_ptr local (new DCPVideoFrame (pvf, frame_count, film->video_frame_rate(), 250000000, RESOLUTION_2K, log_)); - shared_ptr remote (new DCPVideoFrame (pvf, frame_count, film->video_frame_rate(), 250000000, RESOLUTION_2K, log_)); + shared_ptr local (new DCPVideo (pvf, frame_count, film->video_frame_rate(), 250000000, RESOLUTION_2K, log_)); + shared_ptr remote (new DCPVideo (pvf, frame_count, film->video_frame_rate(), 250000000, RESOLUTION_2K, log_)); cout << "Frame " << frame_count << ": "; cout.flush (); diff --git a/src/wx/film_viewer.cc b/src/wx/film_viewer.cc index d84a0af34..dd3d9ebe9 100644 --- a/src/wx/film_viewer.cc +++ b/src/wx/film_viewer.cc @@ -34,7 +34,7 @@ #include "lib/examine_content_job.h" #include "lib/filter.h" #include "lib/player.h" -#include "lib/player_video_frame.h" +#include "lib/player_video.h" #include "lib/video_content.h" #include "lib/video_decoder.h" #include "lib/timer.h" @@ -151,7 +151,7 @@ FilmViewer::get (DCPTime p, bool accurate) return; } - list > pvf = _player->get_video (p, accurate); + list > pvf = _player->get_video (p, accurate); if (!pvf.empty ()) { _frame = pvf.front()->image (); _frame = _frame->scale (_frame->size(), Scaler::from_id ("fastbilinear"), PIX_FMT_RGB24, false); diff --git a/src/wx/film_viewer.h b/src/wx/film_viewer.h index c1c087a14..189b379bf 100644 --- a/src/wx/film_viewer.h +++ b/src/wx/film_viewer.h @@ -28,7 +28,7 @@ class wxToggleButton; class FFmpegPlayer; class Image; class RGBPlusAlphaImage; -class PlayerVideoFrame; +class PlayerVideo; /** @class FilmViewer * @brief A wx widget to view a preview of a Film. -- cgit v1.2.3