From: Carl Hetherington Date: Fri, 31 May 2013 13:19:50 +0000 (+0100) Subject: Various stuff; mostly change to decoder scaling and adding subtitle; scaling test. X-Git-Tag: v2.0.48~1337^2~334 X-Git-Url: https://git.carlh.net/gitweb/?p=dcpomatic.git;a=commitdiff_plain;h=f385ef03e5ea27519a31c0839447735a7fba0602 Various stuff; mostly change to decoder scaling and adding subtitle; scaling test. --- diff --git a/src/lib/ab_transcode_job.cc b/src/lib/ab_transcode_job.cc index 9a883fdd9..2d6f99c91 100644 --- a/src/lib/ab_transcode_job.cc +++ b/src/lib/ab_transcode_job.cc @@ -20,11 +20,8 @@ #include #include "ab_transcode_job.h" #include "film.h" -#include "format.h" -#include "filter.h" #include "ab_transcoder.h" #include "config.h" -#include "encoder.h" #include "i18n.h" diff --git a/src/lib/ab_transcoder.cc b/src/lib/ab_transcoder.cc index 1ec298626..a5659b22f 100644 --- a/src/lib/ab_transcoder.cc +++ b/src/lib/ab_transcoder.cc @@ -50,8 +50,8 @@ ABTranscoder::ABTranscoder (shared_ptr film_a, shared_ptr film_b, sh , _encoder (new Encoder (film_a, j)) , _combiner (new Combiner) { - _player_a->Video.connect (bind (&Combiner::process_video, _combiner, _1, _2, _3, _4)); - _player_b->Video.connect (bind (&Combiner::process_video_b, _combiner, _1, _2, _3, _4)); + _player_a->Video.connect (bind (&Combiner::process_video, _combiner, _1, _2, _3)); + _player_b->Video.connect (bind (&Combiner::process_video_b, _combiner, _1, _2, _3)); _combiner->connect_video (_encoder); _player_a->connect_audio (_encoder); diff --git a/src/lib/combiner.cc b/src/lib/combiner.cc index db490fd34..ca68ef68a 100644 --- a/src/lib/combiner.cc +++ b/src/lib/combiner.cc @@ -32,7 +32,7 @@ Combiner::Combiner () * @param image Frame image. */ void -Combiner::process_video (shared_ptr image, bool, shared_ptr, Time) +Combiner::process_video (shared_ptr image, bool, Time) { _image.reset (new SimpleImage (image)); } @@ -42,7 +42,7 @@ Combiner::process_video (shared_ptr image, bool, shared_ptr image, bool, shared_ptr sub, Time t) +Combiner::process_video_b (shared_ptr image, bool, Time t) { /* Copy the right half of this image into our _image */ /* XXX: this should probably be in the Image class */ @@ -60,6 +60,6 @@ Combiner::process_video_b (shared_ptr image, bool, shared_ptr i, bool, boost::shared_ptr s, Time); - void process_video_b (boost::shared_ptr i, bool, boost::shared_ptr s, Time); + void process_video (boost::shared_ptr i, bool, Time); + void process_video_b (boost::shared_ptr i, bool, Time); private: /** The image that we are currently working on */ diff --git a/src/lib/config.cc b/src/lib/config.cc index c5245bfb4..978428b02 100644 --- a/src/lib/config.cc +++ b/src/lib/config.cc @@ -27,7 +27,7 @@ #include "server.h" #include "scaler.h" #include "filter.h" -#include "container.h" +#include "ratio.h" #include "dcp_content_type.h" #include "sound_processor.h" @@ -106,7 +106,7 @@ Config::read () c = f.optional_string_child ("DefaultContainer"); if (c) { - _default_container = Container::from_id (c.get ()); + _default_container = Ratio::from_id (c.get ()); } c = f.optional_string_child ("DefaultDCPContentType"); @@ -168,7 +168,7 @@ Config::read_old_metadata () } else if (k == "language") { _language = v; } else if (k == "default_container") { - _default_container = Container::from_id (v); + _default_container = Ratio::from_id (v); } else if (k == "default_dcp_content_type") { _default_dcp_content_type = DCPContentType::from_dci_name (v); } else if (k == "dcp_metadata_issuer") { diff --git a/src/lib/config.h b/src/lib/config.h index c43a4f079..110bcc6a8 100644 --- a/src/lib/config.h +++ b/src/lib/config.h @@ -34,8 +34,8 @@ class ServerDescription; class Scaler; class Filter; class SoundProcessor; -class Container; class DCPContentType; +class Ratio; /** @class Config * @brief A singleton class holding configuration. @@ -114,7 +114,7 @@ public: return _default_still_length; } - Container const * default_container () const { + Ratio const * default_container () const { return _default_container; } @@ -193,8 +193,8 @@ public: _default_still_length = s; } - void set_default_container (Container const * f) { - _default_container = f; + void set_default_container (Ratio const * c) { + _default_container = c; } void set_default_dcp_content_type (DCPContentType const * t) { @@ -244,7 +244,7 @@ private: DCIMetadata _default_dci_metadata; boost::optional _language; int _default_still_length; - Container const * _default_container; + Ratio const * _default_container; DCPContentType const * _default_dcp_content_type; libdcp::XMLMetadata _dcp_metadata; diff --git a/src/lib/container.cc b/src/lib/container.cc deleted file mode 100644 index d679e4848..000000000 --- a/src/lib/container.cc +++ /dev/null @@ -1,78 +0,0 @@ -/* - Copyright (C) 2013 Carl Hetherington - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - -*/ - -#include -#include -#include "container.h" - -#include "i18n.h" - -using std::string; -using std::stringstream; -using std::vector; - -vector Container::_containers; - -void -Container::setup_containers () -{ - _containers.push_back (new Container (float(1285) / 1080, "119", _("1.19"), "F")); - _containers.push_back (new Container (float(1436) / 1080, "133", _("4:3"), "F")); - _containers.push_back (new Container (float(1480) / 1080, "137", _("Academy"), "F")); - _containers.push_back (new Container (float(1485) / 1080, "138", _("1.375"), "F")); - _containers.push_back (new Container (float(1793) / 1080, "166", _("1.66"), "F")); - _containers.push_back (new Container (float(1920) / 1080, "178", _("16:9"), "F")); - _containers.push_back (new Container (float(1998) / 1080, "185", _("Flat"), "F")); - _containers.push_back (new Container (float(2048) / 858, "239", _("Scope"), "S")); - _containers.push_back (new Container (float(2048) / 1080, "full-frame", _("Full frame"), "C")); -} - -/** @return A name to be presented to the user */ -string -Container::name () const -{ - return _nickname; -} - -Container const * -Container::from_id (string i) -{ - vector::iterator j = _containers.begin (); - while (j != _containers.end() && (*j)->id() != i) { - ++j; - } - - if (j == _containers.end ()) { - return 0; - } - - return *j; -} - -libdcp::Size -Container::size (libdcp::Size full_frame) const -{ - if (_ratio < static_cast(full_frame.width) / full_frame.height) { - return libdcp::Size (full_frame.height * _ratio, full_frame.height); - } else { - return libdcp::Size (full_frame.width, full_frame.width / _ratio); - } - - return libdcp::Size (); -} diff --git a/src/lib/container.h b/src/lib/container.h deleted file mode 100644 index 4bf03a3f1..000000000 --- a/src/lib/container.h +++ /dev/null @@ -1,70 +0,0 @@ -/* - Copyright (C) 2013 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 - -class Container -{ -public: - Container (float ratio, std::string id, std::string n, std::string d) - : _ratio (ratio) - , _id (id) - , _nickname (n) - , _dci_name (d) - {} - - libdcp::Size size (libdcp::Size) const; - - std::string id () const { - return _id; - } - - std::string name () const; - - /** @return Nickname (e.g. Flat, Scope) */ - std::string nickname () const { - return _nickname; - } - - std::string dci_name () const { - return _dci_name; - } - - float ratio () const { - return _ratio; - } - - static void setup_containers (); - static Container const * from_id (std::string i); - static std::vector all () { - return _containers; - } - -private: - float _ratio; - /** id for use in metadata */ - std::string _id; - /** nickname (e.g. Flat, Scope) */ - std::string _nickname; - std::string _dci_name; - - /** all available containers */ - static std::vector _containers; -}; diff --git a/src/lib/dcp_video_frame.cc b/src/lib/dcp_video_frame.cc index 1c1838df7..2f597522c 100644 --- a/src/lib/dcp_video_frame.cc +++ b/src/lib/dcp_video_frame.cc @@ -53,7 +53,6 @@ #include "scaler.h" #include "image.h" #include "log.h" -#include "subtitle.h" #include "i18n.h" @@ -66,34 +65,21 @@ using libdcp::Size; /** Construct a DCP video frame. * @param input Input image. - * @param out Required size of output, in pixels (including any padding). - * @param s Scaler to use. - * @param p Number of pixels of padding either side of the image. * @param f Index of the frame within the DCP. - * @param fps Frames per second of the Film's source. - * @param pp FFmpeg post-processing string to use. * @param clut Colour look-up table to use (see Config::colour_lut_index ()) * @param bw J2K bandwidth to use (see Config::j2k_bandwidth ()) * @param l Log to write to. */ DCPVideoFrame::DCPVideoFrame ( - shared_ptr yuv, shared_ptr sub, - Size out, int p, int subtitle_offset, float subtitle_scale, - Scaler const * s, int f, int dcp_fps, int clut, int bw, shared_ptr l + shared_ptr image, int f, int dcp_fps, int clut, int bw, shared_ptr l ) - : _input (yuv) - , _subtitle (sub) - , _out_size (out) - , _padding (p) - , _subtitle_offset (subtitle_offset) - , _subtitle_scale (subtitle_scale) - , _scaler (s) + : _image (image) , _frame (f) , _frames_per_second (dcp_fps) , _colour_lut (clut) , _j2k_bandwidth (bw) , _log (l) - , _image (0) + , _opj_image (0) , _parameters (0) , _cinfo (0) , _cio (0) @@ -108,8 +94,8 @@ DCPVideoFrame::create_openjpeg_container () for (int i = 0; i < 3; ++i) { _cmptparm[i].dx = 1; _cmptparm[i].dy = 1; - _cmptparm[i].w = _out_size.width; - _cmptparm[i].h = _out_size.height; + _cmptparm[i].w = _image->size().width; + _cmptparm[i].h = _image->size().height; _cmptparm[i].x0 = 0; _cmptparm[i].y0 = 0; _cmptparm[i].prec = 12; @@ -117,21 +103,21 @@ DCPVideoFrame::create_openjpeg_container () _cmptparm[i].sgnd = 0; } - _image = opj_image_create (3, &_cmptparm[0], CLRSPC_SRGB); - if (_image == 0) { + _opj_image = opj_image_create (3, &_cmptparm[0], CLRSPC_SRGB); + if (_opj_image == 0) { throw EncodeError (N_("could not create libopenjpeg image")); } - _image->x0 = 0; - _image->y0 = 0; - _image->x1 = _out_size.width; - _image->y1 = _out_size.height; + _opj_image->x0 = 0; + _opj_image->y0 = 0; + _opj_image->x1 = _image->size().width; + _opj_image->y1 = _image->size().height; } DCPVideoFrame::~DCPVideoFrame () { - if (_image) { - opj_image_destroy (_image); + if (_opj_image) { + opj_image_destroy (_opj_image); } if (_cio) { @@ -155,19 +141,6 @@ DCPVideoFrame::~DCPVideoFrame () shared_ptr DCPVideoFrame::encode_locally () { - shared_ptr prepared = _input->scale_and_convert_to_rgb (_out_size, _padding, _scaler, true); - - if (_subtitle) { - Rect tx = subtitle_transformed_area ( - float (_out_size.width) / _input->size().width, - float (_out_size.height) / _input->size().height, - _subtitle->area(), _subtitle_offset, _subtitle_scale - ); - - shared_ptr im = _subtitle->image()->scale (tx.size(), _scaler, true); - prepared->alpha_blend (im, tx.position()); - } - create_openjpeg_container (); struct { @@ -181,9 +154,9 @@ DCPVideoFrame::encode_locally () /* Copy our RGB into the openjpeg container, converting to XYZ in the process */ int jn = 0; - for (int y = 0; y < _out_size.height; ++y) { - uint8_t* p = prepared->data()[0] + y * prepared->stride()[0]; - for (int x = 0; x < _out_size.width; ++x) { + for (int y = 0; y < _image->size().height; ++y) { + uint8_t* p = _image->data()[0] + y * _image->stride()[0]; + for (int x = 0; x < _image->size().width; ++x) { /* In gamma LUT (converting 8-bit input to 12-bit) */ s.r = lut_in[_colour_lut][*p++ << 4]; @@ -209,9 +182,9 @@ DCPVideoFrame::encode_locally () d.z = d.z * DCI_COEFFICENT * (DCI_LUT_SIZE - 1); /* Out gamma LUT */ - _image->comps[0].data[jn] = lut_out[LO_DCI][(int) d.x]; - _image->comps[1].data[jn] = lut_out[LO_DCI][(int) d.y]; - _image->comps[2].data[jn] = lut_out[LO_DCI][(int) d.z]; + _opj_image->comps[0].data[jn] = lut_out[LO_DCI][(int) d.x]; + _opj_image->comps[1].data[jn] = lut_out[LO_DCI][(int) d.y]; + _opj_image->comps[2].data[jn] = lut_out[LO_DCI][(int) d.z]; ++jn; } @@ -269,7 +242,7 @@ DCPVideoFrame::encode_locally () /* set max image */ _parameters->max_comp_size = max_comp_size; - _parameters->tcp_rates[0] = ((float) (3 * _image->comps[0].w * _image->comps[0].h * _image->comps[0].prec)) / (max_cs_len * 8); + _parameters->tcp_rates[0] = ((float) (3 * _opj_image->comps[0].w * _opj_image->comps[0].h * _opj_image->comps[0].prec)) / (max_cs_len * 8); /* get a J2K compressor handle */ _cinfo = opj_create_compress (CODEC_J2K); @@ -281,14 +254,14 @@ DCPVideoFrame::encode_locally () _cinfo->event_mgr = 0; /* Setup the encoder parameters using the current image and user parameters */ - opj_setup_encoder (_cinfo, _parameters, _image); + opj_setup_encoder (_cinfo, _parameters, _opj_image); _cio = opj_cio_open ((opj_common_ptr) _cinfo, 0, 0); if (_cio == 0) { throw EncodeError (N_("could not open JPEG2000 stream")); } - int const r = opj_encode (_cinfo, _cio, _image, 0); + int const r = opj_encode (_cinfo, _cio, _opj_image, 0); if (r == 0) { throw EncodeError (N_("JPEG2000 encoding failed")); } @@ -316,42 +289,24 @@ DCPVideoFrame::encode_remotely (ServerDescription const * serv) stringstream s; s << N_("encode please\n") - << N_("input_width ") << _input->size().width << N_("\n") - << N_("input_height ") << _input->size().height << N_("\n") - << N_("input_pixel_format ") << _input->pixel_format() << N_("\n") - << N_("output_width ") << _out_size.width << N_("\n") - << N_("output_height ") << _out_size.height << N_("\n") - << N_("padding ") << _padding << N_("\n") - << N_("subtitle_offset ") << _subtitle_offset << N_("\n") - << N_("subtitle_scale ") << _subtitle_scale << N_("\n") - << N_("scaler ") << _scaler->id () << N_("\n") + << N_("width ") << _image->size().width << N_("\n") + << N_("height ") << _image->size().height << N_("\n") << N_("frame ") << _frame << N_("\n") - << N_("frames_per_second ") << _frames_per_second << N_("\n"); - - s << N_("colour_lut ") << _colour_lut << N_("\n") + << N_("frames_per_second ") << _frames_per_second << N_("\n") + << N_("colour_lut ") << _colour_lut << N_("\n") << N_("j2k_bandwidth ") << _j2k_bandwidth << N_("\n"); - if (_subtitle) { - s << N_("subtitle_x ") << _subtitle->position().x << N_("\n") - << N_("subtitle_y ") << _subtitle->position().y << N_("\n") - << N_("subtitle_width ") << _subtitle->image()->size().width << N_("\n") - << N_("subtitle_height ") << _subtitle->image()->size().height << N_("\n"); - } - _log->log (String::compose ( N_("Sending to remote; pixel format %1, components %2, lines (%3,%4,%5), line sizes (%6,%7,%8)"), - _input->pixel_format(), _input->components(), - _input->lines(0), _input->lines(1), _input->lines(2), - _input->line_size()[0], _input->line_size()[1], _input->line_size()[2] + _image->pixel_format(), _image->components(), + _image->lines(0), _image->lines(1), _image->lines(2), + _image->line_size()[0], _image->line_size()[1], _image->line_size()[2] )); socket->write (s.str().length() + 1); socket->write ((uint8_t *) s.str().c_str(), s.str().length() + 1); - _input->write_to_socket (socket); - if (_subtitle) { - _subtitle->image()->write_to_socket (socket); - } + _image->write_to_socket (socket); shared_ptr e (new RemotelyEncodedData (socket->read_uint32 ())); socket->read (e->data(), e->size()); diff --git a/src/lib/dcp_video_frame.h b/src/lib/dcp_video_frame.h index ba49c95a4..f234b445a 100644 --- a/src/lib/dcp_video_frame.h +++ b/src/lib/dcp_video_frame.h @@ -105,12 +105,8 @@ public: class DCPVideoFrame { public: - DCPVideoFrame ( - boost::shared_ptr, boost::shared_ptr, libdcp::Size, - int, int, float, Scaler const *, int, int, int, int, boost::shared_ptr - ); - - virtual ~DCPVideoFrame (); + DCPVideoFrame (boost::shared_ptr, int, int, int, int, boost::shared_ptr); + ~DCPVideoFrame (); boost::shared_ptr encode_locally (); boost::shared_ptr encode_remotely (ServerDescription const *); @@ -122,13 +118,7 @@ public: private: void create_openjpeg_container (); - boost::shared_ptr _input; ///< the input image - boost::shared_ptr _subtitle; ///< any subtitle that should be on the image - libdcp::Size _out_size; ///< the required size of the output, in pixels - int _padding; - int _subtitle_offset; - float _subtitle_scale; - Scaler const * _scaler; ///< scaler to use + boost::shared_ptr _image; int _frame; ///< frame index within the DCP's intrinsic duration int _frames_per_second; ///< Frames per second that we will use for the DCP int _colour_lut; ///< Colour look-up table to use @@ -137,7 +127,7 @@ private: boost::shared_ptr _log; ///< log opj_image_cmptparm_t _cmptparm[3]; ///< libopenjpeg's opj_image_cmptparm_t - opj_image* _image; ///< libopenjpeg's image container + opj_image* _opj_image; ///< libopenjpeg's image container opj_cparameters_t* _parameters; ///< libopenjpeg's parameters opj_cinfo_t* _cinfo; ///< libopenjpeg's opj_cinfo_t opj_cio_t* _cio; ///< libopenjpeg's opj_cio_t diff --git a/src/lib/encoder.cc b/src/lib/encoder.cc index 3152669ad..f3745ff98 100644 --- a/src/lib/encoder.cc +++ b/src/lib/encoder.cc @@ -22,24 +22,15 @@ */ #include -#include -#include -#include #include "encoder.h" #include "util.h" #include "film.h" #include "log.h" -#include "exceptions.h" -#include "filter.h" #include "config.h" #include "dcp_video_frame.h" #include "server.h" -#include "format.h" #include "cross.h" #include "writer.h" -#include "player.h" -#include "audio_mapping.h" -#include "container.h" #include "i18n.h" @@ -178,7 +169,7 @@ Encoder::frame_done () } void -Encoder::process_video (shared_ptr image, bool same, shared_ptr sub, Time) +Encoder::process_video (shared_ptr image, bool same, Time) { boost::mutex::scoped_lock lock (_mutex); @@ -211,11 +202,8 @@ Encoder::process_video (shared_ptr image, bool same, shared_ptr ( new DCPVideoFrame ( - image, sub, _film->container()->size (_film->full_frame()), 0, - _film->subtitle_offset(), _film->subtitle_scale(), - _film->scaler(), _video_frames_out, _film->dcp_video_frame_rate(), - _film->colour_lut(), _film->j2k_bandwidth(), - _film->log() + image, _video_frames_out, _film->dcp_video_frame_rate(), + _film->colour_lut(), _film->j2k_bandwidth(), _film->log() ) )); diff --git a/src/lib/encoder.h b/src/lib/encoder.h index 6815fa6f6..8f724525c 100644 --- a/src/lib/encoder.h +++ b/src/lib/encoder.h @@ -40,7 +40,6 @@ extern "C" { #include "audio_sink.h" class Image; -class Subtitle; class AudioBuffers; class Film; class ServerDescription; @@ -52,7 +51,7 @@ class Job; /** @class Encoder * @brief Encoder to J2K and WAV for DCP. * - * Video is supplied to process_video as YUV frames, and audio + * Video is supplied to process_video as RGB frames, and audio * is supplied as uncompressed PCM in blocks of various sizes. */ @@ -68,9 +67,8 @@ public: /** Call with a frame of video. * @param i Video frame image. * @param same true if i is the same as the last time we were called. - * @param s A subtitle that should be on this frame, or 0. */ - void process_video (boost::shared_ptr i, bool same, boost::shared_ptr s, Time); + void process_video (boost::shared_ptr i, bool same, Time); /** Call with some audio data */ void process_audio (boost::shared_ptr, Time); diff --git a/src/lib/ffmpeg_decoder.cc b/src/lib/ffmpeg_decoder.cc index a1a6636fb..c148bc530 100644 --- a/src/lib/ffmpeg_decoder.cc +++ b/src/lib/ffmpeg_decoder.cc @@ -39,9 +39,6 @@ extern "C" { } #include #include "film.h" -#include "format.h" -#include "transcoder.h" -#include "job.h" #include "filter.h" #include "exceptions.h" #include "image.h" diff --git a/src/lib/ffmpeg_decoder.h b/src/lib/ffmpeg_decoder.h index c37479612..7b8e1b50c 100644 --- a/src/lib/ffmpeg_decoder.h +++ b/src/lib/ffmpeg_decoder.h @@ -37,8 +37,6 @@ extern "C" { #include "decoder.h" #include "video_decoder.h" #include "audio_decoder.h" -#include "film.h" -#include "ffmpeg_content.h" struct AVFilterGraph; struct AVCodecContext; @@ -52,6 +50,8 @@ class Job; class Options; class Image; class Log; +class FFmpegContent; +class Film; /** @class FFmpegDecoder * @brief A decoder using FFmpeg to decode content. diff --git a/src/lib/film.cc b/src/lib/film.cc index e76d97b59..ef29d35fd 100644 --- a/src/lib/film.cc +++ b/src/lib/film.cc @@ -32,7 +32,6 @@ #include #include #include "film.h" -#include "container.h" #include "job.h" #include "filter.h" #include "util.h" @@ -54,6 +53,7 @@ #include "imagemagick_content.h" #include "sndfile_content.h" #include "dcp_content_type.h" +#include "ratio.h" #include "i18n.h" @@ -426,7 +426,7 @@ Film::read_metadata () { optional c = f.optional_string_child ("Container"); if (c) { - _container = Container::from_id (c.get ()); + _container = Ratio::from_id (c.get ()); } } @@ -602,7 +602,7 @@ Film::set_dcp_content_type (DCPContentType const * t) } void -Film::set_container (Container const * c) +Film::set_container (Ratio const * c) { { boost::mutex::scoped_lock lm (_state_mutex); diff --git a/src/lib/film.h b/src/lib/film.h index 31454c5a7..28beeaed1 100644 --- a/src/lib/film.h +++ b/src/lib/film.h @@ -39,7 +39,6 @@ #include "playlist.h" class DCPContentType; -class Container; class Job; class Filter; class Log; @@ -169,7 +168,7 @@ public: return _dcp_content_type; } - Container const * container () const { + Ratio const * container () const { boost::mutex::scoped_lock lm (_state_mutex); return _container; } @@ -234,7 +233,7 @@ public: void add_content (boost::shared_ptr); void remove_content (boost::shared_ptr); void set_dcp_content_type (DCPContentType const *); - void set_container (Container const *); + void set_container (Ratio const *); void set_scaler (Scaler const *); void set_ab (bool); void set_with_subtitles (bool); @@ -286,7 +285,7 @@ private: /** The type of content that this Film represents (feature, trailer etc.) */ DCPContentType const * _dcp_content_type; /** The container to put this Film in (flat, scope, etc.) */ - Container const * _container; + Ratio const * _container; /** Scaler algorithm to use */ Scaler const * _scaler; /** true to create an A/B comparison DCP, where the left half of the image diff --git a/src/lib/format.cc b/src/lib/format.cc deleted file mode 100644 index 87bdda3d1..000000000 --- a/src/lib/format.cc +++ /dev/null @@ -1,126 +0,0 @@ -/* - Copyright (C) 2012 Carl Hetherington - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - -*/ - -/** @file src/format.cc - * @brief Class to describe a format (aspect ratio) that a Film should - * be shown in. - */ - -#include -#include -#include -#include -#include -#include "format.h" -#include "film.h" -#include "playlist.h" - -#include "i18n.h" - -using std::string; -using std::setprecision; -using std::stringstream; -using std::vector; -using boost::shared_ptr; -using libdcp::Size; - -vector Format::_formats; - -/** @return A name to be presented to the user */ -string -Format::name () const -{ - stringstream s; - if (!_nickname.empty ()) { - s << _nickname << N_(" ("); - } - - s << setprecision(3) << ratio() << N_(":1"); - - if (!_nickname.empty ()) { - s << N_(")"); - } - - return s.str (); -} - -/** Fill our _formats vector with all available formats */ -void -Format::setup_formats () -{ - /// TRANSLATORS: these are film picture aspect ratios; "Academy" means 1.37, "Flat" 1.85 and "Scope" 2.39. - _formats.push_back (new Format (libdcp::Size (1285, 1080), "119", _("1.19"))); - _formats.push_back (new Format (libdcp::Size (1436, 1080), "133", _("4:3"))); - _formats.push_back (new Format (libdcp::Size (1485, 1080), "138", _("1.375"))); - _formats.push_back (new Format (libdcp::Size (1480, 1080), "137", _("Academy"))); - _formats.push_back (new Format (libdcp::Size (1793, 1080), "166", _("1.66"))); - _formats.push_back (new Format (libdcp::Size (1920, 1080), "178", _("16:9"))); - _formats.push_back (new Format (libdcp::Size (1998, 1080), "185", _("Flat"))); - _formats.push_back (new Format (libdcp::Size (2048, 858), "239", _("Scope"))); - _formats.push_back (new Format (libdcp::Size (2048, 1080), "full-frame", _("Full frame"))); -} - -/** @param n Nickname. - * @return Matching Format, or 0. - */ -Format const * -Format::from_nickname (string n) -{ - vector::iterator i = _formats.begin (); - while (i != _formats.end() && (*i)->nickname() != n) { - ++i; - } - - if (i == _formats.end ()) { - return 0; - } - - return *i; -} - -/** @param i Id. - * @return Matching Format, or 0. - */ -Format const * -Format::from_id (string i) -{ - vector::iterator j = _formats.begin (); - while (j != _formats.end() && (*j)->id() != i) { - ++j; - } - - if (j == _formats.end ()) { - return 0; - } - - return *j; -} - -/** @return All available formats */ -vector -Format::all () -{ - return _formats; -} - -float -Format::ratio () const -{ - return static_cast (_dcp_size.width) / _dcp_size.height; -} diff --git a/src/lib/format.h b/src/lib/format.h deleted file mode 100644 index 06423d2b1..000000000 --- a/src/lib/format.h +++ /dev/null @@ -1,80 +0,0 @@ -/* - Copyright (C) 2012 Carl Hetherington - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - -*/ - -/** @file src/format.h - * @brief Classes to describe a format (aspect ratio) that a Film should - * be shown in. - */ - -#include -#include -#include - -class Film; - -class Format -{ -public: - Format (libdcp::Size dcp, std::string id, std::string n) - : _dcp_size (dcp) - , _id (id) - , _nickname (n) - {} - - /** @return size in pixels of the images that we should - * put in a DCP for this format. - */ - libdcp::Size dcp_size () const { - return _dcp_size; - } - - std::string id () const { - return _id; - } - - /** @return Full name to present to the user */ - std::string name () const; - - /** @return Nickname (e.g. Flat, Scope) */ - std::string nickname () const { - return _nickname; - } - - static Format const * from_nickname (std::string n); - static Format const * from_id (std::string i); - static std::vector all (); - static void setup_formats (); - -protected: - /** @return the ratio */ - float ratio () const; - - /** libdcp::Size in pixels of the images that we should - * put in a DCP for this format. - */ - libdcp::Size _dcp_size; - /** id for use in metadata */ - std::string _id; - /** nickname (e.g. Flat, Scope) */ - std::string _nickname; - -private: - /** all available formats */ - static std::vector _formats; -}; diff --git a/src/lib/image.cc b/src/lib/image.cc index b166dfac6..a12c61b3e 100644 --- a/src/lib/image.cc +++ b/src/lib/image.cc @@ -121,7 +121,7 @@ Image::scale (libdcp::Size out_size, Scaler const * scaler, bool result_aligned) * @param scaler Scaler to use. */ shared_ptr -Image::scale_and_convert_to_rgb (libdcp::Size out_size, int padding, Scaler const * scaler, bool result_aligned) const +Image::scale_and_convert_to_rgb (libdcp::Size out_size, Scaler const * scaler, bool result_aligned) const { assert (scaler); /* Empirical testing suggests that sws_scale() will crash if @@ -129,14 +129,11 @@ Image::scale_and_convert_to_rgb (libdcp::Size out_size, int padding, Scaler cons */ assert (aligned ()); - libdcp::Size content_size = out_size; - content_size.width -= (padding * 2); - - shared_ptr rgb (new SimpleImage (PIX_FMT_RGB24, content_size, result_aligned)); + shared_ptr rgb (new SimpleImage (PIX_FMT_RGB24, out_size, result_aligned)); struct SwsContext* scale_context = sws_getContext ( size().width, size().height, pixel_format(), - content_size.width, content_size.height, PIX_FMT_RGB24, + out_size.width, out_size.height, PIX_FMT_RGB24, scaler->ffmpeg_id (), 0, 0, 0 ); @@ -148,28 +145,6 @@ Image::scale_and_convert_to_rgb (libdcp::Size out_size, int padding, Scaler cons rgb->data(), rgb->stride() ); - /* Put the image in the right place in a black frame if are padding; this is - a bit grubby and expensive, but probably inconsequential in the great - scheme of things. - */ - if (padding > 0) { - shared_ptr padded_rgb (new SimpleImage (PIX_FMT_RGB24, out_size, result_aligned)); - padded_rgb->make_black (); - - /* XXX: we are cheating a bit here; we know the frame is RGB so we can - make assumptions about its composition. - */ - uint8_t* p = padded_rgb->data()[0] + padding * 3; - uint8_t* q = rgb->data()[0]; - for (int j = 0; j < rgb->lines(0); ++j) { - memcpy (p, q, rgb->line_size()[0]); - p += padded_rgb->stride()[0]; - q += rgb->stride()[0]; - } - - rgb = padded_rgb; - } - sws_freeContext (scale_context); return rgb; @@ -376,6 +351,21 @@ Image::alpha_blend (shared_ptr other, Position position) } } +void +Image::copy (shared_ptr other, Position position) +{ + /* Only implemented for RGB24 onto RGB24 so far */ + assert (_pixel_format == PIX_FMT_RGB24 && other->pixel_format() == PIX_FMT_RGB24); + assert (position.x >= 0 && position.y >= 0); + + int const N = min (position.x + other->size().width, size().width) - position.x; + for (int ty = position.y, oy = 0; ty < size().height && oy < other->size().height; ++ty, ++oy) { + uint8_t * const tp = data()[0] + ty * stride()[0] + position.x * 3; + uint8_t * const op = other->data()[0] + oy * other->stride()[0]; + memcpy (tp, op, N * 3); + } +} + void Image::read_from_socket (shared_ptr socket) { diff --git a/src/lib/image.h b/src/lib/image.h index 34f87b188..f9bda7460 100644 --- a/src/lib/image.h +++ b/src/lib/image.h @@ -71,10 +71,11 @@ public: int components () const; int lines (int) const; - boost::shared_ptr scale_and_convert_to_rgb (libdcp::Size out_size, int padding, Scaler const * scaler, bool aligned) const; + boost::shared_ptr scale_and_convert_to_rgb (libdcp::Size, Scaler const *, bool) const; boost::shared_ptr scale (libdcp::Size, Scaler const *, bool aligned) const; boost::shared_ptr post_process (std::string, bool aligned) const; void alpha_blend (boost::shared_ptr image, Position pos); + void copy (boost::shared_ptr image, Position pos); boost::shared_ptr crop (Crop c, bool aligned) const; void make_black (); diff --git a/src/lib/player.cc b/src/lib/player.cc index 2926796ef..e64e1e011 100644 --- a/src/lib/player.cc +++ b/src/lib/player.cc @@ -119,6 +119,7 @@ Player::pass () } if (!earliest) { + flush (); return true; } @@ -144,7 +145,7 @@ Player::pass () } void -Player::process_video (weak_ptr weak_content, shared_ptr image, bool same, shared_ptr sub, Time time) +Player::process_video (weak_ptr weak_content, shared_ptr image, bool same, Time time) { shared_ptr content = weak_content.lock (); if (!content) { @@ -153,7 +154,7 @@ Player::process_video (weak_ptr weak_content, shared_ptr i time += content->start (); - Video (image, same, sub, time); + Video (image, same, time); } void @@ -192,6 +193,18 @@ Player::process_audio (weak_ptr weak_content, shared_ptrframes()); } +void +Player::flush () +{ + if (_audio_buffers.frames() > 0) { + shared_ptr emit (new AudioBuffers (_audio_buffers.channels(), _audio_buffers.frames())); + emit->copy_from (&_audio_buffers, _audio_buffers.frames(), 0, 0); + Audio (emit, _next_audio); + _next_audio += _film->audio_frames_to_time (_audio_buffers.frames ()); + _audio_buffers.set_frames (0); + } +} + /** @return true on error */ void Player::seek (Time t) @@ -236,7 +249,7 @@ Player::add_black_piece (Time s, Time len) { shared_ptr nc (new NullContent (_film, s, len)); shared_ptr bd (new BlackDecoder (_film, nc)); - bd->Video.connect (bind (&Player::process_video, this, nc, _1, _2, _3, _4)); + bd->Video.connect (bind (&Player::process_video, this, nc, _1, _2, _3)); _pieces.push_back (shared_ptr (new Piece (nc, bd))); cout << "\tblack @ " << s << " -- " << (s + len) << "\n"; } @@ -274,7 +287,7 @@ Player::setup_pieces () if (fc) { shared_ptr fd (new FFmpegDecoder (_film, fc, _video, _audio, _subtitles)); - fd->Video.connect (bind (&Player::process_video, this, *i, _1, _2, _3, _4)); + fd->Video.connect (bind (&Player::process_video, this, *i, _1, _2, _3)); fd->Audio.connect (bind (&Player::process_audio, this, *i, _1, _2)); decoder = fd; @@ -295,7 +308,7 @@ Player::setup_pieces () if (!id) { id.reset (new ImageMagickDecoder (_film, ic)); - id->Video.connect (bind (&Player::process_video, this, *i, _1, _2, _3, _4)); + id->Video.connect (bind (&Player::process_video, this, *i, _1, _2, _3)); } decoder = id; diff --git a/src/lib/player.h b/src/lib/player.h index cdedf1676..cce2bdc21 100644 --- a/src/lib/player.h +++ b/src/lib/player.h @@ -62,7 +62,7 @@ public: private: - void process_video (boost::weak_ptr, boost::shared_ptr, bool, boost::shared_ptr, Time); + void process_video (boost::weak_ptr, boost::shared_ptr, bool, Time); void process_audio (boost::weak_ptr, boost::shared_ptr, Time); void setup_pieces (); void playlist_changed (); @@ -70,6 +70,7 @@ private: void do_seek (Time, bool); void add_black_piece (Time, Time); void add_silent_piece (Time, Time); + void flush (); boost::shared_ptr _film; boost::shared_ptr _playlist; diff --git a/src/lib/ratio.cc b/src/lib/ratio.cc new file mode 100644 index 000000000..5988b3418 --- /dev/null +++ b/src/lib/ratio.cc @@ -0,0 +1,71 @@ +/* + Copyright (C) 2013 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 "ratio.h" + +#include "i18n.h" + +using std::string; +using std::stringstream; +using std::vector; + +vector Ratio::_ratios; + +libdcp::Size +Ratio::size (libdcp::Size full_frame) const +{ + if (_ratio < static_cast(full_frame.width) / full_frame.height) { + return libdcp::Size (full_frame.height * _ratio, full_frame.height); + } else { + return libdcp::Size (full_frame.width, full_frame.width / _ratio); + } + + return libdcp::Size (); +} + + +void +Ratio::setup_ratios () +{ + _ratios.push_back (new Ratio (float(1285) / 1080, "119", _("1.19"), "F")); + _ratios.push_back (new Ratio (float(1436) / 1080, "133", _("4:3"), "F")); + _ratios.push_back (new Ratio (float(1480) / 1080, "137", _("Academy"), "F")); + _ratios.push_back (new Ratio (float(1485) / 1080, "138", _("1.375"), "F")); + _ratios.push_back (new Ratio (float(1793) / 1080, "166", _("1.66"), "F")); + _ratios.push_back (new Ratio (float(1920) / 1080, "178", _("16:9"), "F")); + _ratios.push_back (new Ratio (float(1998) / 1080, "185", _("Flat"), "F")); + _ratios.push_back (new Ratio (float(2048) / 858, "239", _("Scope"), "S")); + _ratios.push_back (new Ratio (float(2048) / 1080, "full-frame", _("Full frame"), "C")); +} + +Ratio const * +Ratio::from_id (string i) +{ + vector::iterator j = _ratios.begin (); + while (j != _ratios.end() && (*j)->id() != i) { + ++j; + } + + if (j == _ratios.end ()) { + return 0; + } + + return *j; +} diff --git a/src/lib/ratio.h b/src/lib/ratio.h new file mode 100644 index 000000000..6916a7491 --- /dev/null +++ b/src/lib/ratio.h @@ -0,0 +1,66 @@ +/* + Copyright (C) 2013 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 + +class Ratio +{ +public: + Ratio (float ratio, std::string id, std::string n, std::string d) + : _ratio (ratio) + , _id (id) + , _nickname (n) + , _dci_name (d) + {} + + libdcp::Size size (libdcp::Size) const; + + std::string id () const { + return _id; + } + + std::string nickname () const { + return _nickname; + } + + std::string dci_name () const { + return _dci_name; + } + + float ratio () const { + return _ratio; + } + + static void setup_ratios (); + static Ratio const * from_id (std::string i); + static std::vector all () { + return _ratios; + } + +private: + float _ratio; + /** id for use in metadata */ + std::string _id; + /** nickname (e.g. Flat, Scope) */ + std::string _nickname; + std::string _dci_name; + + static std::vector _ratios; +}; diff --git a/src/lib/server.cc b/src/lib/server.cc index 07b826946..5ca04c692 100644 --- a/src/lib/server.cc +++ b/src/lib/server.cc @@ -98,44 +98,25 @@ Server::process (shared_ptr socket) stringstream s (buffer.get()); multimap kv = read_key_value (s); - if (get_required_string (kv, N_("encode")) != N_("please")) { + if (get_required_string (kv, "encode") != "please") { return -1; } - libdcp::Size in_size (get_required_int (kv, N_("input_width")), get_required_int (kv, N_("input_height"))); - int pixel_format_int = get_required_int (kv, N_("input_pixel_format")); - libdcp::Size out_size (get_required_int (kv, N_("output_width")), get_required_int (kv, N_("output_height"))); - int padding = get_required_int (kv, N_("padding")); - int subtitle_offset = get_required_int (kv, N_("subtitle_offset")); - float subtitle_scale = get_required_float (kv, N_("subtitle_scale")); - string scaler_id = get_required_string (kv, N_("scaler")); - int frame = get_required_int (kv, N_("frame")); - int frames_per_second = get_required_int (kv, N_("frames_per_second")); - int colour_lut_index = get_required_int (kv, N_("colour_lut")); - int j2k_bandwidth = get_required_int (kv, N_("j2k_bandwidth")); - Position subtitle_position (get_optional_int (kv, N_("subtitle_x")), get_optional_int (kv, N_("subtitle_y"))); - libdcp::Size subtitle_size (get_optional_int (kv, N_("subtitle_width")), get_optional_int (kv, N_("subtitle_height"))); + libdcp::Size size (get_required_int (kv, "width"), get_required_int (kv, "height")); + int frame = get_required_int (kv, "frame"); + int frames_per_second = get_required_int (kv, "frames_per_second"); + int colour_lut_index = get_required_int (kv, "colour_lut"); + int j2k_bandwidth = get_required_int (kv, "j2k_bandwidth"); /* 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); - - shared_ptr image (new SimpleImage (pixel_format, in_size, true)); + shared_ptr image (new SimpleImage (PIX_FMT_RGB24, size, true)); image->read_from_socket (socket); - shared_ptr sub; - if (subtitle_size.width && subtitle_size.height) { - shared_ptr subtitle_image (new SimpleImage (PIX_FMT_RGBA, subtitle_size, true)); - 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, colour_lut_index, j2k_bandwidth, _log + image, frame, frames_per_second, colour_lut_index, j2k_bandwidth, _log ); shared_ptr encoded = dcp_video_frame.encode_locally (); diff --git a/src/lib/transcode_job.cc b/src/lib/transcode_job.cc index f9a305367..ce02fa57e 100644 --- a/src/lib/transcode_job.cc +++ b/src/lib/transcode_job.cc @@ -25,10 +25,8 @@ #include #include "transcode_job.h" #include "film.h" -#include "format.h" #include "transcoder.h" #include "log.h" -#include "encoder.h" #include "i18n.h" diff --git a/src/lib/util.cc b/src/lib/util.cc index e1bc560c6..71a21105b 100644 --- a/src/lib/util.cc +++ b/src/lib/util.cc @@ -56,12 +56,11 @@ extern "C" { #include "util.h" #include "exceptions.h" #include "scaler.h" -#include "format.h" #include "dcp_content_type.h" #include "filter.h" #include "sound_processor.h" #include "config.h" -#include "container.h" +#include "ratio.h" #ifdef DVDOMATIC_WINDOWS #include "stack.hpp" #endif @@ -285,8 +284,7 @@ dcpomatic_setup () avfilter_register_all (); - Format::setup_formats (); - Container::setup_containers (); + Ratio::setup_ratios (); DCPContentType::setup_dcp_content_types (); Scaler::setup_scalers (); Filter::setup_filters (); diff --git a/src/lib/video_content.cc b/src/lib/video_content.cc index ae799dad3..18a128a5d 100644 --- a/src/lib/video_content.cc +++ b/src/lib/video_content.cc @@ -20,22 +20,26 @@ #include #include "video_content.h" #include "video_decoder.h" +#include "ratio.h" #include "i18n.h" -int const VideoContentProperty::VIDEO_SIZE = 0; +int const VideoContentProperty::VIDEO_SIZE = 0; int const VideoContentProperty::VIDEO_FRAME_RATE = 1; -int const VideoContentProperty::VIDEO_CROP = 2; +int const VideoContentProperty::VIDEO_CROP = 2; +int const VideoContentProperty::VIDEO_RATIO = 3; using std::string; using std::stringstream; using std::setprecision; using boost::shared_ptr; using boost::lexical_cast; +using boost::optional; VideoContent::VideoContent (shared_ptr f, Time s, ContentVideoFrame len) : Content (f, s) , _video_length (len) + , _ratio (0) { } @@ -43,6 +47,7 @@ VideoContent::VideoContent (shared_ptr f, Time s, ContentVideoFrame VideoContent::VideoContent (shared_ptr f, boost::filesystem::path p) : Content (f, p) , _video_length (0) + , _ratio (0) { } @@ -58,6 +63,10 @@ VideoContent::VideoContent (shared_ptr f, shared_ptrnumber_child ("RightCrop"); _crop.top = node->number_child ("TopCrop"); _crop.bottom = node->number_child ("BottomCrop"); + optional r = node->optional_string_child ("Ratio"); + if (r) { + _ratio = Ratio::from_id (r.get ()); + } } VideoContent::VideoContent (VideoContent const & o) @@ -65,6 +74,7 @@ VideoContent::VideoContent (VideoContent const & o) , _video_length (o._video_length) , _video_size (o._video_size) , _video_frame_rate (o._video_frame_rate) + , _ratio (o._ratio) { } @@ -81,6 +91,9 @@ VideoContent::as_xml (xmlpp::Node* node) const node->add_child("RightCrop")->add_child_text (boost::lexical_cast (_crop.right)); node->add_child("TopCrop")->add_child_text (boost::lexical_cast (_crop.top)); node->add_child("BottomCrop")->add_child_text (boost::lexical_cast (_crop.bottom)); + if (_ratio) { + node->add_child("Ratio")->add_child_text (_ratio->id ()); + } } void @@ -191,3 +204,17 @@ VideoContent::set_bottom_crop (int c) signal_changed (VideoContentProperty::VIDEO_CROP); } +void +VideoContent::set_ratio (Ratio const * r) +{ + { + boost::mutex::scoped_lock lm (_mutex); + if (_ratio == r) { + return; + } + + _ratio = r; + } + + signal_changed (VideoContentProperty::VIDEO_RATIO); +} diff --git a/src/lib/video_content.h b/src/lib/video_content.h index ce2550d12..44f1c2847 100644 --- a/src/lib/video_content.h +++ b/src/lib/video_content.h @@ -24,6 +24,7 @@ #include "util.h" class VideoDecoder; +class Ratio; class VideoContentProperty { @@ -31,6 +32,7 @@ public: static int const VIDEO_SIZE; static int const VIDEO_FRAME_RATE; static int const VIDEO_CROP; + static int const VIDEO_RATIO; }; class VideoContent : public virtual Content @@ -70,6 +72,13 @@ public: return _crop; } + void set_ratio (Ratio const *); + + Ratio const * ratio () const { + boost::mutex::scoped_lock lm (_mutex); + return _ratio; + } + protected: void take_from_video_decoder (boost::shared_ptr); @@ -79,6 +88,7 @@ private: libdcp::Size _video_size; float _video_frame_rate; Crop _crop; + Ratio const * _ratio; }; #endif diff --git a/src/lib/video_decoder.cc b/src/lib/video_decoder.cc index 609594e76..cba21d280 100644 --- a/src/lib/video_decoder.cc +++ b/src/lib/video_decoder.cc @@ -1,5 +1,3 @@ -/* -*- c-basic-offset: 8; default-tab-width: 8; -*- */ - /* Copyright (C) 2012 Carl Hetherington @@ -23,6 +21,7 @@ #include "subtitle.h" #include "film.h" #include "image.h" +#include "ratio.h" #include "i18n.h" @@ -52,18 +51,45 @@ VideoDecoder::video (shared_ptr image, bool same, Time t) return; } + image->crop (_video_content->crop(), true); + + shared_ptr film = _film.lock (); + assert (film); + + libdcp::Size const container_size = film->container()->size (film->full_frame ()); + libdcp::Size const image_size = _video_content->ratio()->size (container_size); + + shared_ptr out = image->scale_and_convert_to_rgb (image_size, film->scaler(), true); + shared_ptr sub; if (_timed_subtitle && _timed_subtitle->displayed_at (t)) { sub = _timed_subtitle->subtitle (); } - Video (image, same, sub, t); + if (sub) { + Rect const tx = subtitle_transformed_area ( + float (image_size.width) / video_size().width, + float (image_size.height) / video_size().height, + sub->area(), film->subtitle_offset(), film->subtitle_scale() + ); - shared_ptr film = _film.lock (); - assert (film); + shared_ptr im = sub->image()->scale (tx.size(), film->scaler(), true); + out->alpha_blend (im, tx.position()); + } + + if (image_size != container_size) { + assert (image_size.width <= container_size.width); + assert (image_size.height <= container_size.height); + shared_ptr im (new SimpleImage (PIX_FMT_RGB24, container_size, true)); + im->make_black (); + im->copy (out, Position ((container_size.width - image_size.width) / 2, (container_size.height - image_size.height) / 2)); + out = im; + } + + Video (out, same, t); if (_frame_rate_conversion.repeat) { - Video (image, true, sub, t + film->video_frames_to_time (1)); + Video (image, true, t + film->video_frames_to_time (1)); _next_video = t + film->video_frames_to_time (2); } else { _next_video = t + film->video_frames_to_time (1); diff --git a/src/lib/video_sink.h b/src/lib/video_sink.h index 2da42528c..957aeb4b4 100644 --- a/src/lib/video_sink.h +++ b/src/lib/video_sink.h @@ -32,9 +32,8 @@ public: /** Call with a frame of video. * @param i Video frame image. * @param same true if i is the same as last time we were called. - * @param s A subtitle that should be on this frame, or 0. */ - virtual void process_video (boost::shared_ptr i, bool same, boost::shared_ptr s, Time) = 0; + virtual void process_video (boost::shared_ptr i, bool same, Time) = 0; }; #endif diff --git a/src/lib/video_source.cc b/src/lib/video_source.cc index 39043c860..824587bcb 100644 --- a/src/lib/video_source.cc +++ b/src/lib/video_source.cc @@ -25,11 +25,11 @@ using boost::weak_ptr; using boost::bind; static void -process_video_proxy (weak_ptr sink, shared_ptr image, bool same, shared_ptr sub, Time time) +process_video_proxy (weak_ptr sink, shared_ptr image, bool same, Time time) { shared_ptr p = sink.lock (); if (p) { - p->process_video (image, same, sub, time); + p->process_video (image, same, time); } } @@ -39,6 +39,6 @@ VideoSource::connect_video (shared_ptr s) /* If we bind, say, a Player (as the VideoSink) to a Decoder (which is owned by the Player) we create a cycle. Use a weak_ptr to break it. */ - Video.connect (bind (process_video_proxy, weak_ptr (s), _1, _2, _3, _4)); + Video.connect (bind (process_video_proxy, weak_ptr (s), _1, _2, _3)); } diff --git a/src/lib/video_source.h b/src/lib/video_source.h index c94b5a20a..9242af444 100644 --- a/src/lib/video_source.h +++ b/src/lib/video_source.h @@ -42,10 +42,9 @@ public: /** Emitted when a video frame is ready. * First parameter is the video image. * Second parameter is true if the image is the same as the last one that was emitted. - * Third parameter is either 0 or a subtitle that should be on this frame. - * Fourth parameter is the time relative to the start of this source's content. + * Third parameter is the time relative to the start of this source's content. */ - boost::signals2::signal, bool, boost::shared_ptr, Time)> Video; + boost::signals2::signal, bool, Time)> Video; void connect_video (boost::shared_ptr); }; diff --git a/src/lib/writer.cc b/src/lib/writer.cc index 22aacb640..e9f7ab582 100644 --- a/src/lib/writer.cc +++ b/src/lib/writer.cc @@ -27,7 +27,7 @@ #include "writer.h" #include "compose.hpp" #include "film.h" -#include "container.h" +#include "ratio.h" #include "log.h" #include "dcp_video_frame.h" #include "dcp_content_type.h" @@ -133,6 +133,7 @@ Writer::fake_write (int frame) void Writer::write (shared_ptr audio) { + cout << "W: audio " << audio->frames() << "\n"; _sound_asset_writer->write (audio->data(), audio->frames()); } diff --git a/src/lib/wscript b/src/lib/wscript index 54941df42..6e69b98b2 100644 --- a/src/lib/wscript +++ b/src/lib/wscript @@ -14,7 +14,6 @@ sources = """ black_decoder.cc config.cc combiner.cc - container.cc content.cc cross.cc dci_metadata.cc @@ -30,7 +29,6 @@ sources = """ ffmpeg_decoder.cc film.cc filter.cc - format.cc image.cc imagemagick_content.cc imagemagick_decoder.cc @@ -41,6 +39,7 @@ sources = """ null_content.cc player.cc playlist.cc + ratio.cc scp_dcp_job.cc scaler.cc server.cc diff --git a/src/tools/dcpomatic.cc b/src/tools/dcpomatic.cc index 196045a9b..8d3de53ff 100644 --- a/src/tools/dcpomatic.cc +++ b/src/tools/dcpomatic.cc @@ -36,12 +36,8 @@ #include "wx/properties_dialog.h" #include "wx/wx_ui_signaller.h" #include "lib/film.h" -#include "lib/format.h" #include "lib/config.h" -#include "lib/filter.h" #include "lib/util.h" -#include "lib/scaler.h" -#include "lib/exceptions.h" #include "lib/version.h" #include "lib/ui_signaller.h" #include "lib/log.h" diff --git a/src/tools/dcpomatic_cli.cc b/src/tools/dcpomatic_cli.cc index c295a011d..c7b7e3b3d 100644 --- a/src/tools/dcpomatic_cli.cc +++ b/src/tools/dcpomatic_cli.cc @@ -21,7 +21,6 @@ #include #include #include -#include "format.h" #include "film.h" #include "filter.h" #include "transcode_job.h" diff --git a/src/wx/config_dialog.cc b/src/wx/config_dialog.cc index ae5bed723..3efd7857a 100644 --- a/src/wx/config_dialog.cc +++ b/src/wx/config_dialog.cc @@ -28,7 +28,7 @@ #include #include "lib/config.h" #include "lib/server.h" -#include "lib/container.h" +#include "lib/ratio.h" #include "lib/scaler.h" #include "lib/filter.h" #include "lib/dcp_content_type.h" @@ -171,10 +171,10 @@ ConfigDialog::make_misc_panel () _default_dci_metadata_button->Connect (wxID_ANY, wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler (ConfigDialog::edit_default_dci_metadata_clicked), 0, this); - vector fmt = Container::all (); + vector ratio = Ratio::all (); int n = 0; - for (vector::iterator i = fmt.begin(); i != fmt.end(); ++i) { - _default_container->Append (std_to_wx ((*i)->name ())); + for (vector::iterator i = ratio.begin(); i != ratio.end(); ++i) { + _default_container->Append (std_to_wx ((*i)->nickname ())); if (*i == config->default_container ()) { _default_container->SetSelection (n); } @@ -535,8 +535,8 @@ ConfigDialog::default_still_length_changed (wxCommandEvent &) void ConfigDialog::default_container_changed (wxCommandEvent &) { - vector fmt = Container::all (); - Config::instance()->set_default_container (fmt[_default_container->GetSelection()]); + vector ratio = Ratio::all (); + Config::instance()->set_default_container (ratio[_default_container->GetSelection()]); } void diff --git a/src/wx/film_editor.cc b/src/wx/film_editor.cc index 75867d1d5..bddce18be 100644 --- a/src/wx/film_editor.cc +++ b/src/wx/film_editor.cc @@ -29,15 +29,14 @@ #include #include #include -#include "lib/format.h" #include "lib/film.h" #include "lib/transcode_job.h" #include "lib/exceptions.h" #include "lib/ab_transcode_job.h" #include "lib/job_manager.h" #include "lib/filter.h" +#include "lib/ratio.h" #include "lib/config.h" -#include "lib/ffmpeg_decoder.h" #include "lib/imagemagick_content.h" #include "lib/sndfile_content.h" #include "lib/dcp_content_type.h" @@ -52,7 +51,6 @@ #include "imagemagick_content_dialog.h" #include "timeline_dialog.h" #include "audio_mapping_view.h" -#include "container.h" #include "timecode.h" using std::string; @@ -86,7 +84,7 @@ FilmEditor::FilmEditor (shared_ptr f, wxWindow* parent) make_dcp_panel (); _main_notebook->AddPage (_dcp_panel, _("DCP"), false); - setup_formats (); + setup_ratios (); set_film (f); connect_to_widgets (); @@ -167,9 +165,9 @@ FilmEditor::make_dcp_panel () _scaler->Append (std_to_wx ((*i)->name())); } - vector const co = Container::all (); - for (vector::const_iterator i = co.begin(); i != co.end(); ++i) { - _container->Append (std_to_wx ((*i)->name ())); + vector const ratio = Ratio::all (); + for (vector::const_iterator i = ratio.begin(); i != ratio.end(); ++i) { + _container->Append (std_to_wx ((*i)->nickname ())); } vector const ct = DCPContentType::all (); @@ -259,8 +257,8 @@ FilmEditor::make_video_panel () ++r; add_label_to_grid_bag_sizer (grid, _video_panel, _("Scale to"), wxGBPosition (r, 0)); - _format = new wxChoice (_video_panel, wxID_ANY); - grid->Add (_format, wxGBPosition (r, 1)); + _ratio = new wxChoice (_video_panel, wxID_ANY); + grid->Add (_ratio, wxGBPosition (r, 1)); ++r; _scaling_description = new wxStaticText (_video_panel, wxID_ANY, wxT ("\n \n \n \n"), wxDefaultPosition, wxDefaultSize); @@ -598,8 +596,8 @@ FilmEditor::film_changed (Film::Property p) break; case Film::CONTENT: setup_content (); - setup_formats (); -// setup_format (); + setup_ratios (); +// setup_ratio (); setup_subtitle_control_sensitivity (); setup_show_audio_sensitivity (); break; @@ -765,14 +763,14 @@ void FilmEditor::setup_container () { int n = 0; - vector containers = Container::all (); - vector::iterator i = containers.begin (); - while (i != containers.end() && *i != _film->container ()) { + vector ratios = Ratio::all (); + vector::iterator i = ratios.begin (); + while (i != ratios.end() && *i != _film->container ()) { ++i; ++n; } - if (i == containers.end()) { + if (i == ratios.end()) { checked_set (_container, -1); } else { checked_set (_container, n); @@ -792,9 +790,9 @@ FilmEditor::container_changed (wxCommandEvent &) int const n = _container->GetSelection (); if (n >= 0) { - vector containers = Container::all (); - assert (n < int (containers.size())); - _film->set_container (containers[n]); + vector ratios = Ratio::all (); + assert (n < int (ratios.size())); + _film->set_container (ratios[n]); } } @@ -878,7 +876,7 @@ FilmEditor::set_things_sensitive (bool s) _name->Enable (s); _use_dci_name->Enable (s); _edit_dci_button->Enable (s); - _format->Enable (s); + _ratio->Enable (s); _content->Enable (s); _left_crop->Enable (s); _right_crop->Enable (s); @@ -999,13 +997,13 @@ FilmEditor::audio_gain_calculate_button_clicked (wxCommandEvent &) } void -FilmEditor::setup_formats () +FilmEditor::setup_ratios () { - _formats = Format::all (); + _ratios = Ratio::all (); - _format->Clear (); - for (vector::iterator i = _formats.begin(); i != _formats.end(); ++i) { - _format->Append (std_to_wx ((*i)->name ())); + _ratio->Clear (); + for (vector::iterator i = _ratios.begin(); i != _ratios.end(); ++i) { + _ratio->Append (std_to_wx ((*i)->nickname ())); } _dcp_sizer->Layout (); diff --git a/src/wx/film_editor.h b/src/wx/film_editor.h index c34cd73e0..be1bf7c36 100644 --- a/src/wx/film_editor.h +++ b/src/wx/film_editor.h @@ -35,7 +35,7 @@ class Film; class AudioDialog; class TimelineDialog; class AudioMappingView; -class Format; +class Ratio; class Timecode; /** @class FilmEditor @@ -102,7 +102,7 @@ private: void film_content_changed (boost::weak_ptr, int); void set_things_sensitive (bool); - void setup_formats (); + void setup_ratios (); void setup_subtitle_control_sensitivity (); void setup_dcp_name (); void setup_show_audio_sensitivity (); @@ -144,8 +144,8 @@ private: wxCheckBox* _loop_content; wxSpinCtrl* _loop_count; wxButton* _edit_dci_button; - wxChoice* _format; - wxStaticText* _format_description; + wxChoice* _ratio; + wxStaticText* _ratio_description; wxStaticText* _scaling_description; wxSpinCtrl* _left_crop; wxSpinCtrl* _right_crop; @@ -173,7 +173,7 @@ private: Timecode* _start; Timecode* _length; - std::vector _formats; + std::vector _ratios; bool _generally_sensitive; AudioDialog* _audio_dialog; diff --git a/src/wx/film_viewer.cc b/src/wx/film_viewer.cc index 97185ca94..26f99db11 100644 --- a/src/wx/film_viewer.cc +++ b/src/wx/film_viewer.cc @@ -27,11 +27,9 @@ #include #include #include "lib/film.h" -#include "lib/container.h" -#include "lib/format.h" +#include "lib/ratio.h" #include "lib/util.h" #include "lib/job_manager.h" -#include "lib/subtitle.h" #include "lib/image.h" #include "lib/scaler.h" #include "lib/exceptions.h" @@ -166,7 +164,7 @@ FilmViewer::set_film (shared_ptr f) on and off without needing obtain a new Player. */ - _player->Video.connect (bind (&FilmViewer::process_video, this, _1, _2, _3, _4)); + _player->Video.connect (bind (&FilmViewer::process_video, this, _1, _2, _3)); _film->Changed.connect (boost::bind (&FilmViewer::film_changed, this, _1)); _film->ContentChanged.connect (boost::bind (&FilmViewer::film_content_changed, this, _1, _2)); @@ -233,12 +231,6 @@ FilmViewer::paint_panel (wxPaintEvent &) wxBitmap frame_bitmap (frame); dc.DrawBitmap (frame_bitmap, _display_frame_x, 0); - if (_film->with_subtitles() && _display_sub) { - wxImage sub (_display_sub->size().width, _display_sub->size().height, _display_sub->data()[0], _display_sub->alpha(), true); - wxBitmap sub_bitmap (sub); - dc.DrawBitmap (sub_bitmap, _display_sub_position.x, _display_sub_position.y); - } - if (_out_size.width < _panel_size.width) { wxPen p (GetBackgroundColour ()); wxBrush b (GetBackgroundColour ()); @@ -301,29 +293,7 @@ FilmViewer::raw_to_display () } /* Get a compacted image as we have to feed it to wxWidgets */ - _display_frame = _raw_frame->scale_and_convert_to_rgb (_film_size, 0, _film->scaler(), false); - - if (_raw_sub) { - - /* Our output is already cropped by the decoder, so we need to account for that - when working out the scale that we are applying. - */ - - /* XXX */ - Size const cropped_size = _raw_frame->size ();//_film->cropped_size (_raw_frame->size ()); - - Rect tx = subtitle_transformed_area ( - float (_film_size.width) / cropped_size.width, - float (_film_size.height) / cropped_size.height, - _raw_sub->area(), _film->subtitle_offset(), _film->subtitle_scale() - ); - - _display_sub.reset (new RGBPlusAlphaImage (_raw_sub->image()->scale (tx.size(), _film->scaler(), false))); - _display_sub_position = tx.position(); - _display_sub_position.x += _display_frame_x; - } else { - _display_sub.reset (); - } + _display_frame = _raw_frame->scale_and_convert_to_rgb (_film_size, _film->scaler(), false); } void @@ -333,7 +303,7 @@ FilmViewer::calculate_sizes () return; } - Container const * container = _film->container (); + Ratio const * container = _film->container (); float const panel_ratio = static_cast (_panel_size.width) / _panel_size.height; float const film_ratio = container ? container->ratio () : 1.78; @@ -386,10 +356,9 @@ FilmViewer::check_play_state () } void -FilmViewer::process_video (shared_ptr image, bool, shared_ptr sub, Time t) +FilmViewer::process_video (shared_ptr image, bool, Time t) { _raw_frame = image; - _raw_sub = sub; raw_to_display (); diff --git a/src/wx/film_viewer.h b/src/wx/film_viewer.h index 68d51bfbd..39755ed35 100644 --- a/src/wx/film_viewer.h +++ b/src/wx/film_viewer.h @@ -28,7 +28,6 @@ class wxToggleButton; class FFmpegPlayer; class Image; class RGBPlusAlphaImage; -class Subtitle; /** @class FilmViewer * @brief A wx widget to view a preview of a Film. @@ -38,14 +37,12 @@ class Subtitle; * 1. get_frame() asks our _player to decode some data. If it does, process_video() * will be called. * - * 2. process_video() takes the image and subtitle from the decoder (_raw_frame and _raw_sub) - * and calls raw_to_display(). + * 2. process_video() takes the image from the decoder (_raw_frame) and calls raw_to_display(). * * 3. raw_to_display() copies _raw_frame to _display_frame, processing it and scaling it. * * 4. calling _panel->Refresh() and _panel->Update() results in paint_panel() being called; - * this creates frame_bitmap from _display_frame and blits it to the display. It also - * blits the subtitle, if required. + * this creates frame_bitmap from _display_frame and blits it to the display. * * update_from_decoder() asks the player to re-emit its current frame on the next pass(), and then * starts from step #1. @@ -67,7 +64,7 @@ private: void slider_moved (wxScrollEvent &); void play_clicked (wxCommandEvent &); void timer (wxTimerEvent &); - void process_video (boost::shared_ptr, bool, boost::shared_ptr, Time); + void process_video (boost::shared_ptr, bool, Time); void calculate_sizes (); void check_play_state (); void update_from_raw (); @@ -92,14 +89,11 @@ private: wxTimer _timer; boost::shared_ptr _raw_frame; - boost::shared_ptr _raw_sub; boost::shared_ptr _display_frame; /* The x offset at which we display the actual film content; this corresponds to the film's padding converted to our coordinates. */ int _display_frame_x; - boost::shared_ptr _display_sub; - Position _display_sub_position; bool _got_frame; /** Size of our output (including padding if we have any) */ diff --git a/test/client_server_test.cc b/test/client_server_test.cc index 9c4482d3c..51b52331a 100644 --- a/test/client_server_test.cc +++ b/test/client_server_test.cc @@ -63,12 +63,6 @@ BOOST_AUTO_TEST_CASE (client_server_test) shared_ptr frame ( new DCPVideoFrame ( image, - subtitle, - libdcp::Size (1998, 1080), - 0, - 0, - 1, - Scaler::from_id ("bicubic"), 0, 24, 0, diff --git a/test/container_test.cc b/test/container_test.cc deleted file mode 100644 index 825a8cdc4..000000000 --- a/test/container_test.cc +++ /dev/null @@ -1,73 +0,0 @@ -/* - Copyright (C) 2012 Carl Hetherington - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - -*/ - -using std::ostream; - -namespace libdcp { - -ostream& -operator<< (ostream& s, libdcp::Size const & t) -{ - s << t.width << "x" << t.height; - return s; -} - -} - -BOOST_AUTO_TEST_CASE (container_test) -{ - Container::setup_containers (); - - Container const * c = Container::from_id ("119"); - BOOST_CHECK (c); - BOOST_CHECK_EQUAL (c->size(libdcp::Size (2048, 1080)), libdcp::Size (1285, 1080)); - - c = Container::from_id ("133"); - BOOST_CHECK (c); - BOOST_CHECK_EQUAL (c->size(libdcp::Size (2048, 1080)), libdcp::Size (1436, 1080)); - - c = Container::from_id ("137"); - BOOST_CHECK (c); - BOOST_CHECK_EQUAL (c->size(libdcp::Size (2048, 1080)), libdcp::Size (1480, 1080)); - - c = Container::from_id ("138"); - BOOST_CHECK (c); - BOOST_CHECK_EQUAL (c->size(libdcp::Size (2048, 1080)), libdcp::Size (1485, 1080)); - - c = Container::from_id ("166"); - BOOST_CHECK (c); - BOOST_CHECK_EQUAL (c->size(libdcp::Size (2048, 1080)), libdcp::Size (1793, 1080)); - - c = Container::from_id ("178"); - BOOST_CHECK (c); - BOOST_CHECK_EQUAL (c->size(libdcp::Size (2048, 1080)), libdcp::Size (1920, 1080)); - - c = Container::from_id ("185"); - BOOST_CHECK (c); - BOOST_CHECK_EQUAL (c->size(libdcp::Size (2048, 1080)), libdcp::Size (1998, 1080)); - - c = Container::from_id ("239"); - BOOST_CHECK (c); - BOOST_CHECK_EQUAL (c->size(libdcp::Size (2048, 1080)), libdcp::Size (2048, 858)); - - c = Container::from_id ("full-frame"); - BOOST_CHECK (c); - BOOST_CHECK_EQUAL (c->size(libdcp::Size (2048, 1080)), libdcp::Size (2048, 1080)); -} - diff --git a/test/dcp_test.cc b/test/dcp_test.cc index 795b4dfe3..cf31d674e 100644 --- a/test/dcp_test.cc +++ b/test/dcp_test.cc @@ -29,7 +29,7 @@ BOOST_AUTO_TEST_CASE (make_dcp_test) dcpomatic_sleep (1); } - film->set_container (Container::from_id ("185")); + film->set_container (Ratio::from_id ("185")); film->set_dcp_content_type (DCPContentType::from_pretty_name ("Test")); film->make_dcp (); film->write_metadata (); diff --git a/test/film_metadata_test.cc b/test/film_metadata_test.cc index 315461b22..397b9e43a 100644 --- a/test/film_metadata_test.cc +++ b/test/film_metadata_test.cc @@ -32,7 +32,7 @@ BOOST_AUTO_TEST_CASE (film_metadata_test) f->set_name ("fred"); f->set_dcp_content_type (DCPContentType::from_pretty_name ("Short")); - f->set_container (Container::from_id ("185")); + f->set_container (Ratio::from_id ("185")); f->set_ab (true); f->write_metadata (); @@ -45,7 +45,7 @@ BOOST_AUTO_TEST_CASE (film_metadata_test) BOOST_CHECK_EQUAL (g->name(), "fred"); BOOST_CHECK_EQUAL (g->dcp_content_type(), DCPContentType::from_pretty_name ("Short")); - BOOST_CHECK_EQUAL (g->container(), Container::from_id ("185")); + BOOST_CHECK_EQUAL (g->container(), Ratio::from_id ("185")); BOOST_CHECK_EQUAL (g->ab(), true); g->write_metadata (); diff --git a/test/format_test.cc b/test/format_test.cc deleted file mode 100644 index 71bc00359..000000000 --- a/test/format_test.cc +++ /dev/null @@ -1,33 +0,0 @@ -/* - Copyright (C) 2012 Carl Hetherington - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - -*/ - -BOOST_AUTO_TEST_CASE (format_test) -{ - Format::setup_formats (); - - Format const * f = Format::from_nickname ("Flat"); - BOOST_CHECK (f); - BOOST_CHECK_EQUAL (f->dcp_size().width, 1998); - BOOST_CHECK_EQUAL (f->dcp_size().height, 1080); - - f = Format::from_nickname ("Scope"); - BOOST_CHECK (f); - BOOST_CHECK_EQUAL (f->dcp_size().width, 2048); - BOOST_CHECK_EQUAL (f->dcp_size().height, 858); -} diff --git a/test/make_black_test.cc b/test/make_black_test.cc index 3c0b979ff..c70870915 100644 --- a/test/make_black_test.cc +++ b/test/make_black_test.cc @@ -40,7 +40,7 @@ BOOST_AUTO_TEST_CASE (make_black_test) for (list::const_iterator i = pix_fmts.begin(); i != pix_fmts.end(); ++i) { boost::shared_ptr foo (new SimpleImage (*i, in_size, true)); foo->make_black (); - boost::shared_ptr bar = foo->scale_and_convert_to_rgb (out_size, 0, Scaler::from_id ("bicubic"), true); + boost::shared_ptr bar = foo->scale_and_convert_to_rgb (out_size, Scaler::from_id ("bicubic"), true); uint8_t* p = bar->data()[0]; for (int y = 0; y < bar->size().height; ++y) { diff --git a/test/ratio_test.cc b/test/ratio_test.cc new file mode 100644 index 000000000..6311976a3 --- /dev/null +++ b/test/ratio_test.cc @@ -0,0 +1,73 @@ +/* + Copyright (C) 2012 Carl Hetherington + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +using std::ostream; + +namespace libdcp { + +ostream& +operator<< (ostream& s, libdcp::Size const & t) +{ + s << t.width << "x" << t.height; + return s; +} + +} + +BOOST_AUTO_TEST_CASE (ratio_test) +{ + Ratio::setup_ratios (); + + Ratio const * r = Ratio::from_id ("119"); + BOOST_CHECK (r); + BOOST_CHECK_EQUAL (r->size(libdcp::Size (2048, 1080)), libdcp::Size (1285, 1080)); + + r = Ratio::from_id ("133"); + BOOST_CHECK (r); + BOOST_CHECK_EQUAL (r->size(libdcp::Size (2048, 1080)), libdcp::Size (1436, 1080)); + + r = Ratio::from_id ("137"); + BOOST_CHECK (r); + BOOST_CHECK_EQUAL (r->size(libdcp::Size (2048, 1080)), libdcp::Size (1480, 1080)); + + r = Ratio::from_id ("138"); + BOOST_CHECK (r); + BOOST_CHECK_EQUAL (r->size(libdcp::Size (2048, 1080)), libdcp::Size (1485, 1080)); + + r = Ratio::from_id ("166"); + BOOST_CHECK (r); + BOOST_CHECK_EQUAL (r->size(libdcp::Size (2048, 1080)), libdcp::Size (1793, 1080)); + + r = Ratio::from_id ("178"); + BOOST_CHECK (r); + BOOST_CHECK_EQUAL (r->size(libdcp::Size (2048, 1080)), libdcp::Size (1920, 1080)); + + r = Ratio::from_id ("185"); + BOOST_CHECK (r); + BOOST_CHECK_EQUAL (r->size(libdcp::Size (2048, 1080)), libdcp::Size (1998, 1080)); + + r = Ratio::from_id ("239"); + BOOST_CHECK (r); + BOOST_CHECK_EQUAL (r->size(libdcp::Size (2048, 1080)), libdcp::Size (2048, 858)); + + r = Ratio::from_id ("full-frame"); + BOOST_CHECK (r); + BOOST_CHECK_EQUAL (r->size(libdcp::Size (2048, 1080)), libdcp::Size (2048, 1080)); +} + diff --git a/test/scaling_test.cc b/test/scaling_test.cc index 60009f10b..dba611043 100644 --- a/test/scaling_test.cc +++ b/test/scaling_test.cc @@ -17,15 +17,56 @@ */ +#include "imagemagick_content.h" + /** @file test/scaling_test.cc * @brief Test scaling and black-padding of images from a still-image source. */ using boost::shared_ptr; +static void scaling_test_for (shared_ptr film, shared_ptr content, string image, string container) +{ + content->set_ratio (Ratio::from_id (image)); + film->set_container (Ratio::from_id (container)); + film->make_dcp (); + + while (JobManager::instance()->work_to_do ()); + + BOOST_CHECK (!JobManager::instance()->errors()); + + boost::filesystem::path ref; + ref = "test"; + ref /= "data"; + ref /= "scaling_test_" + image + "_" + container; + + boost::filesystem::path check; + check = "build"; + check /= "test"; + check /= "scaling_test"; + check /= film->dcp_name(); + + check_dcp (ref.string(), check.string()); +} + BOOST_AUTO_TEST_CASE (scaling_test) { shared_ptr film = new_test_film ("scaling_test"); - film->examine_and_add_content (shared_ptr (new ImageMagickContent ("test/data/simple_testcard_640x480.png"))); + film->set_dcp_content_type (DCPContentType::from_dci_name ("FTR")); + film->set_name ("scaling_test"); + shared_ptr imc (new ImageMagickContent (film, "test/data/simple_testcard_640x480.png")); + + film->examine_and_add_content (imc); + while (JobManager::instance()->work_to_do ()); + imc->set_video_length (1); + + scaling_test_for (film, imc, "133", "185"); + scaling_test_for (film, imc, "185", "185"); + scaling_test_for (film, imc, "239", "185"); + + scaling_test_for (film, imc, "133", "239"); + scaling_test_for (film, imc, "185", "239"); + scaling_test_for (film, imc, "239", "239"); } + diff --git a/test/test.cc b/test/test.cc index 7d49bb66a..2837729c5 100644 --- a/test/test.cc +++ b/test/test.cc @@ -22,7 +22,8 @@ #include #include #include -#include "format.h" +#include +#include "ratio.h" #include "film.h" #include "filter.h" #include "job_manager.h" @@ -40,7 +41,6 @@ #include "ffmpeg_decoder.h" #include "sndfile_decoder.h" #include "dcp_content_type.h" -#include "container.h" #define BOOST_TEST_DYN_LINK #define BOOST_TEST_MODULE dcpomatic_test #include @@ -49,6 +49,8 @@ using std::string; using std::list; using std::stringstream; using std::vector; +using std::min; +using std::cout; using boost::shared_ptr; using boost::thread; using boost::dynamic_pointer_cast; @@ -93,13 +95,67 @@ new_test_film (string name) return f; } +void +check_file (string ref, string check) +{ + uintmax_t N = boost::filesystem::file_size (ref); + BOOST_CHECK_EQUAL (N, boost::filesystem::file_size(check)); + FILE* ref_file = fopen (ref.c_str(), "rb"); + BOOST_CHECK (ref_file); + FILE* check_file = fopen (check.c_str(), "rb"); + BOOST_CHECK (check_file); + + int const buffer_size = 65536; + uint8_t* ref_buffer = new uint8_t[buffer_size]; + uint8_t* check_buffer = new uint8_t[buffer_size]; + + while (N) { + uintmax_t this_time = min (uintmax_t (buffer_size), N); + size_t r = fread (ref_buffer, 1, this_time, ref_file); + BOOST_CHECK_EQUAL (r, this_time); + r = fread (check_buffer, 1, this_time, check_file); + BOOST_CHECK_EQUAL (r, this_time); + + BOOST_CHECK_EQUAL (memcmp (ref_buffer, check_buffer, this_time), 0); + N -= this_time; + } + + delete[] ref_buffer; + delete[] check_buffer; + + fclose (ref_file); + fclose (check_file); +} + +static void +note (libdcp::NoteType, string n) +{ + cout << n << "\n"; +} + +void +check_dcp (string ref, string check) +{ + libdcp::DCP ref_dcp (ref); + ref_dcp.read (); + libdcp::DCP check_dcp (check); + check_dcp.read (); + + libdcp::EqualityOptions options; + options.max_mean_pixel_error = 5; + options.max_std_dev_pixel_error = 5; + options.max_audio_sample_error = 255; + + BOOST_CHECK (ref_dcp.equals (check_dcp, options, boost::bind (note, _1, _2))); +} + + #include "scaling_test.cc" -#include "container_test.cc" +#include "ratio_test.cc" #include "pixel_formats_test.cc" #include "make_black_test.cc" #include "film_metadata_test.cc" #include "stream_test.cc" -#include "format_test.cc" #include "util_test.cc" #include "dcp_test.cc" #include "frame_rate_test.cc"