From 39c65e47432c76a4e34aaea5317bd7362409aed0 Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Thu, 17 Jan 2013 21:30:16 +0000 Subject: Try to tidy up frame indexing; use DCP length obtained from the transcode to make the DCP. --- src/lib/server.cc | 1 + 1 file changed, 1 insertion(+) (limited to 'src/lib/server.cc') diff --git a/src/lib/server.cc b/src/lib/server.cc index bea75cff8..134cb65a0 100644 --- a/src/lib/server.cc +++ b/src/lib/server.cc @@ -45,6 +45,7 @@ using boost::algorithm::is_any_of; using boost::algorithm::split; using boost::thread; using boost::bind; +using libdcp::Size; /** Create a server description from a string of metadata returned from as_metadata(). * @param v Metadata. -- cgit v1.2.3 From d1b20374b1bd02b2929c9c3080c006874b525ef5 Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Wed, 23 Jan 2013 20:06:37 +0000 Subject: Remove multi-reel, for now, and sort out Size vs libdcp::Size. --- src/lib/dcp_video_frame.cc | 2 +- src/lib/dcp_video_frame.h | 8 ++-- src/lib/ffmpeg_decoder.cc | 8 ++-- src/lib/ffmpeg_decoder.h | 2 +- src/lib/film.cc | 32 ++------------- src/lib/film.h | 20 +++------- src/lib/filter_graph.cc | 4 +- src/lib/filter_graph.h | 6 +-- src/lib/format.cc | 30 +++++++------- src/lib/format.h | 12 +++--- src/lib/image.cc | 16 ++++---- src/lib/image.h | 16 ++++---- src/lib/imagemagick_decoder.cc | 6 +-- src/lib/imagemagick_decoder.h | 2 +- src/lib/make_dcp_job.cc | 90 +++++++++++++++--------------------------- src/lib/make_dcp_job.h | 2 +- src/lib/matcher.h | 2 +- src/lib/options.h | 2 +- src/lib/server.cc | 6 +-- src/lib/subtitle.cc | 2 +- src/lib/util.cc | 13 +----- src/lib/util.h | 34 ++-------------- src/lib/video_decoder.h | 2 +- src/wx/film_editor.cc | 60 ---------------------------- src/wx/film_editor.h | 5 --- src/wx/film_viewer.cc | 4 +- src/wx/film_viewer.h | 2 +- test/test.cc | 14 +++---- 28 files changed, 119 insertions(+), 283 deletions(-) (limited to 'src/lib/server.cc') diff --git a/src/lib/dcp_video_frame.cc b/src/lib/dcp_video_frame.cc index c6b29ba41..921a1876b 100644 --- a/src/lib/dcp_video_frame.cc +++ b/src/lib/dcp_video_frame.cc @@ -75,7 +75,7 @@ using boost::shared_ptr; */ DCPVideoFrame::DCPVideoFrame ( shared_ptr yuv, shared_ptr sub, - Size out, int p, int subtitle_offset, float subtitle_scale, + libdcp::Size out, int p, int subtitle_offset, float subtitle_scale, Scaler const * s, SourceFrame f, float fps, string pp, int clut, int bw, Log* l ) : _input (yuv) diff --git a/src/lib/dcp_video_frame.h b/src/lib/dcp_video_frame.h index 134720da8..c0eff3f35 100644 --- a/src/lib/dcp_video_frame.h +++ b/src/lib/dcp_video_frame.h @@ -40,7 +40,7 @@ class EncodedData { public: /** @param d Data (will not be freed by this class, but may be by subclasses) - * @param s Size of data, in bytes. + * @param s libdcp::Size of data, in bytes. */ EncodedData (uint8_t* d, int s) : _data (d) @@ -76,7 +76,7 @@ class LocallyEncodedData : public EncodedData { public: /** @param d Data (which will not be freed by this class) - * @param s Size of data, in bytes. + * @param s libdcp::Size of data, in bytes. */ LocallyEncodedData (uint8_t* d, int s) : EncodedData (d, s) @@ -107,7 +107,7 @@ class DCPVideoFrame { public: DCPVideoFrame ( - boost::shared_ptr, boost::shared_ptr, Size, + boost::shared_ptr, boost::shared_ptr, libdcp::Size, int, int, float, Scaler const *, SourceFrame, float, std::string, int, int, Log * ); @@ -125,7 +125,7 @@ private: boost::shared_ptr _input; ///< the input image boost::shared_ptr _subtitle; ///< any subtitle that should be on the image - Size _out_size; ///< the required size of the output, in pixels + libdcp::Size _out_size; ///< the required size of the output, in pixels int _padding; int _subtitle_offset; float _subtitle_scale; diff --git a/src/lib/ffmpeg_decoder.cc b/src/lib/ffmpeg_decoder.cc index a19f26ad7..aff3ff666 100644 --- a/src/lib/ffmpeg_decoder.cc +++ b/src/lib/ffmpeg_decoder.cc @@ -468,10 +468,10 @@ FFmpegDecoder::audio_sample_format () const return _audio_codec_context->sample_fmt; } -Size +libdcp::Size FFmpegDecoder::native_size () const { - return Size (_video_codec_context->width, _video_codec_context->height); + return libdcp::Size (_video_codec_context->width, _video_codec_context->height); } PixelFormat @@ -558,12 +558,12 @@ FFmpegDecoder::filter_and_emit_video (AVFrame* frame) shared_ptr graph; list >::iterator i = _filter_graphs.begin(); - while (i != _filter_graphs.end() && !(*i)->can_process (Size (frame->width, frame->height), (AVPixelFormat) frame->format)) { + while (i != _filter_graphs.end() && !(*i)->can_process (libdcp::Size (frame->width, frame->height), (AVPixelFormat) frame->format)) { ++i; } if (i == _filter_graphs.end ()) { - graph.reset (new FilterGraph (_film, this, Size (frame->width, frame->height), (AVPixelFormat) frame->format)); + graph.reset (new FilterGraph (_film, this, libdcp::Size (frame->width, frame->height), (AVPixelFormat) frame->format)); _filter_graphs.push_back (graph); _film->log()->log (String::compose ("New graph for %1x%2, pixel format %3", frame->width, frame->height, frame->format)); } else { diff --git a/src/lib/ffmpeg_decoder.h b/src/lib/ffmpeg_decoder.h index 2fb8675f9..3b564b826 100644 --- a/src/lib/ffmpeg_decoder.h +++ b/src/lib/ffmpeg_decoder.h @@ -90,7 +90,7 @@ public: ~FFmpegDecoder (); float frames_per_second () const; - Size native_size () const; + libdcp::Size native_size () const; SourceFrame length () const; int time_base_numerator () const; int time_base_denominator () const; diff --git a/src/lib/film.cc b/src/lib/film.cc index f0441c9e0..5a11b0ca9 100644 --- a/src/lib/film.cc +++ b/src/lib/film.cc @@ -157,7 +157,6 @@ Film::Film (Film const & o) , _scaler (o._scaler) , _dcp_trim_start (o._dcp_trim_start) , _dcp_trim_end (o._dcp_trim_end) - , _reel_size (o._reel_size) , _dcp_ab (o._dcp_ab) , _content_audio_stream (o._content_audio_stream) , _external_audio (o._external_audio) @@ -414,9 +413,6 @@ Film::write_metadata () const f << "scaler " << _scaler->id () << "\n"; f << "dcp_trim_start " << _dcp_trim_start << "\n"; f << "dcp_trim_end " << _dcp_trim_end << "\n"; - if (_reel_size) { - f << "reel_size " << _reel_size.get() << "\n"; - } f << "dcp_ab " << (_dcp_ab ? "1" : "0") << "\n"; if (_content_audio_stream) { f << "selected_content_audio_stream " << _content_audio_stream->to_string() << "\n"; @@ -531,8 +527,6 @@ Film::read_metadata () _dcp_trim_start = atoi (v.c_str ()); } else if (k == "dcp_trim_end") { _dcp_trim_end = atoi (v.c_str ()); - } else if (k == "reel_size") { - _reel_size = boost::lexical_cast (v); } else if (k == "dcp_ab") { _dcp_ab = (v == "1"); } else if (k == "selected_content_audio_stream" || (!version && k == "selected_audio_stream")) { @@ -628,8 +622,8 @@ Film::read_metadata () _dirty = false; } -Size -Film::cropped_size (Size s) const +libdcp::Size +Film::cropped_size (libdcp::Size s) const { boost::mutex::scoped_lock lm (_state_mutex); s.width -= _crop.left + _crop.right; @@ -1094,26 +1088,6 @@ Film::set_dcp_trim_end (int t) signal_changed (DCP_TRIM_END); } -void -Film::set_reel_size (uint64_t s) -{ - { - boost::mutex::scoped_lock lm (_state_mutex); - _reel_size = s; - } - signal_changed (REEL_SIZE); -} - -void -Film::unset_reel_size () -{ - { - boost::mutex::scoped_lock lm (_state_mutex); - _reel_size = boost::optional (); - } - signal_changed (REEL_SIZE); -} - void Film::set_dcp_ab (bool a) { @@ -1323,7 +1297,7 @@ Film::set_package_type (string p) } void -Film::set_size (Size s) +Film::set_size (libdcp::Size s) { { boost::mutex::scoped_lock lm (_state_mutex); diff --git a/src/lib/film.h b/src/lib/film.h index 3485dfaae..d3530b817 100644 --- a/src/lib/film.h +++ b/src/lib/film.h @@ -86,7 +86,7 @@ public: void write_metadata () const; void read_metadata (); - Size cropped_size (Size) const; + libdcp::Size cropped_size (libdcp::Size) const; boost::optional dcp_length () const; std::string dci_name () const; std::string dcp_name () const; @@ -116,7 +116,6 @@ public: SCALER, DCP_TRIM_START, DCP_TRIM_END, - REEL_SIZE, DCP_AB, CONTENT_AUDIO_STREAM, EXTERNAL_AUDIO, @@ -201,11 +200,6 @@ public: return _dcp_trim_end; } - boost::optional reel_size () const { - boost::mutex::scoped_lock lm (_state_mutex); - return _reel_size; - } - bool dcp_ab () const { boost::mutex::scoped_lock lm (_state_mutex); return _dcp_ab; @@ -306,7 +300,7 @@ public: return _package_type; } - Size size () const { + libdcp::Size size () const { boost::mutex::scoped_lock lm (_state_mutex); return _size; } @@ -361,8 +355,6 @@ public: void set_scaler (Scaler const *); void set_dcp_trim_start (int); void set_dcp_trim_end (int); - void set_reel_size (uint64_t); - void unset_reel_size (); void set_dcp_ab (bool); void set_content_audio_stream (boost::shared_ptr); void set_external_audio (std::vector); @@ -383,7 +375,7 @@ public: void set_studio (std::string); void set_facility (std::string); void set_package_type (std::string); - void set_size (Size); + void set_size (libdcp::Size); void set_length (SourceFrame); void unset_length (); void set_content_digest (std::string); @@ -445,8 +437,6 @@ private: int _dcp_trim_start; /** Frames to trim off the end of the DCP */ int _dcp_trim_end; - /** Approximate target reel size in bytes; if not set, use a single reel */ - boost::optional _reel_size; /** true to create an A/B comparison DCP, where the left half of the image is the video without any filters or post-processing, and the right half has the specified filters and post-processing. @@ -494,8 +484,8 @@ private: /* Data which are cached to speed things up */ - /** Size, in pixels, of the source (ignoring cropping) */ - Size _size; + /** libdcp::Size, in pixels, of the source (ignoring cropping) */ + libdcp::Size _size; /** The length of the source, in video frames (as far as we know) */ boost::optional _length; /** MD5 digest of our content file */ diff --git a/src/lib/filter_graph.cc b/src/lib/filter_graph.cc index 376ab404f..6cd7dc2cb 100644 --- a/src/lib/filter_graph.cc +++ b/src/lib/filter_graph.cc @@ -54,7 +54,7 @@ using boost::shared_ptr; * @param s Size of the images to process. * @param p Pixel format of the images to process. */ -FilterGraph::FilterGraph (shared_ptr film, FFmpegDecoder* decoder, Size s, AVPixelFormat p) +FilterGraph::FilterGraph (shared_ptr film, FFmpegDecoder* decoder, libdcp::Size s, AVPixelFormat p) : _buffer_src_context (0) , _buffer_sink_context (0) , _size (s) @@ -205,7 +205,7 @@ FilterGraph::process (AVFrame const * frame) * @return true if this chain can process images with `s' and `p', otherwise false. */ bool -FilterGraph::can_process (Size s, AVPixelFormat p) const +FilterGraph::can_process (libdcp::Size s, AVPixelFormat p) const { return (_size == s && _pixel_format == p); } diff --git a/src/lib/filter_graph.h b/src/lib/filter_graph.h index 9e6ac6252..7e4e8422b 100644 --- a/src/lib/filter_graph.h +++ b/src/lib/filter_graph.h @@ -37,15 +37,15 @@ class FFmpegDecoder; class FilterGraph { public: - FilterGraph (boost::shared_ptr film, FFmpegDecoder* decoder, Size s, AVPixelFormat p); + FilterGraph (boost::shared_ptr film, FFmpegDecoder* decoder, libdcp::Size s, AVPixelFormat p); - bool can_process (Size s, AVPixelFormat p) const; + bool can_process (libdcp::Size s, AVPixelFormat p) const; std::list > process (AVFrame const * frame); private: AVFilterContext* _buffer_src_context; AVFilterContext* _buffer_sink_context; - Size _size; ///< size of the images that this chain can process + libdcp::Size _size; ///< size of the images that this chain can process AVPixelFormat _pixel_format; ///< pixel format of the images that this chain can process }; diff --git a/src/lib/format.cc b/src/lib/format.cc index 975862411..088a16059 100644 --- a/src/lib/format.cc +++ b/src/lib/format.cc @@ -67,19 +67,19 @@ Format::as_metadata () const void Format::setup_formats () { - _formats.push_back (new FixedFormat (119, Size (1285, 1080), "119", "1.19", "F")); - _formats.push_back (new FixedFormat (133, Size (1436, 1080), "133", "1.33", "F")); - _formats.push_back (new FixedFormat (138, Size (1485, 1080), "138", "1.375", "F")); - _formats.push_back (new FixedFormat (133, Size (1998, 1080), "133-in-flat", "4:3 within Flat", "F")); - _formats.push_back (new FixedFormat (137, Size (1480, 1080), "137", "Academy", "F")); - _formats.push_back (new FixedFormat (166, Size (1793, 1080), "166", "1.66", "F")); - _formats.push_back (new FixedFormat (166, Size (1998, 1080), "166-in-flat", "1.66 within Flat", "F")); - _formats.push_back (new FixedFormat (178, Size (1998, 1080), "178-in-flat", "16:9 within Flat", "F")); - _formats.push_back (new FixedFormat (178, Size (1920, 1080), "178", "16:9", "F")); - _formats.push_back (new FixedFormat (185, Size (1998, 1080), "185", "Flat", "F")); - _formats.push_back (new FixedFormat (239, Size (2048, 858), "239", "Scope", "S")); - _formats.push_back (new VariableFormat (Size (1998, 1080), "var-185", "Flat", "F")); - _formats.push_back (new VariableFormat (Size (2048, 858), "var-239", "Scope", "S")); + _formats.push_back (new FixedFormat (119, libdcp::Size (1285, 1080), "119", "1.19", "F")); + _formats.push_back (new FixedFormat (133, libdcp::Size (1436, 1080), "133", "1.33", "F")); + _formats.push_back (new FixedFormat (138, libdcp::Size (1485, 1080), "138", "1.375", "F")); + _formats.push_back (new FixedFormat (133, libdcp::Size (1998, 1080), "133-in-flat", "4:3 within Flat", "F")); + _formats.push_back (new FixedFormat (137, libdcp::Size (1480, 1080), "137", "Academy", "F")); + _formats.push_back (new FixedFormat (166, libdcp::Size (1793, 1080), "166", "1.66", "F")); + _formats.push_back (new FixedFormat (166, libdcp::Size (1998, 1080), "166-in-flat", "1.66 within Flat", "F")); + _formats.push_back (new FixedFormat (178, libdcp::Size (1998, 1080), "178-in-flat", "16:9 within Flat", "F")); + _formats.push_back (new FixedFormat (178, libdcp::Size (1920, 1080), "178", "16:9", "F")); + _formats.push_back (new FixedFormat (185, libdcp::Size (1998, 1080), "185", "Flat", "F")); + _formats.push_back (new FixedFormat (239, libdcp::Size (2048, 858), "239", "Scope", "S")); + _formats.push_back (new VariableFormat (libdcp::Size (1998, 1080), "var-185", "Flat", "F")); + _formats.push_back (new VariableFormat (libdcp::Size (2048, 858), "var-239", "Scope", "S")); } /** @param n Nickname. @@ -140,7 +140,7 @@ Format::all () * @param id ID (e.g. 185) * @param n Nick name (e.g. Flat) */ -FixedFormat::FixedFormat (int r, Size dcp, string id, string n, string d) +FixedFormat::FixedFormat (int r, libdcp::Size dcp, string id, string n, string d) : Format (dcp, id, n, d) , _ratio (r) { @@ -160,7 +160,7 @@ Format::dcp_padding (shared_ptr f) const return p; } -VariableFormat::VariableFormat (Size dcp, string id, string n, string d) +VariableFormat::VariableFormat (libdcp::Size dcp, string id, string n, string d) : Format (dcp, id, n, d) { diff --git a/src/lib/format.h b/src/lib/format.h index 2118237a4..b4c691e56 100644 --- a/src/lib/format.h +++ b/src/lib/format.h @@ -31,7 +31,7 @@ class Film; class Format { public: - Format (Size dcp, std::string id, std::string n, std::string d) + Format (libdcp::Size dcp, std::string id, std::string n, std::string d) : _dcp_size (dcp) , _id (id) , _nickname (n) @@ -52,7 +52,7 @@ public: * put in a DCP for this ratio. This size will not correspond * to the ratio when we are doing things like 16:9 in a Flat frame. */ - Size dcp_size () const { + libdcp::Size dcp_size () const { return _dcp_size; } @@ -81,11 +81,11 @@ public: static void setup_formats (); protected: - /** Size in pixels of the images that we should + /** libdcp::Size in pixels of the images that we should * put in a DCP for this ratio. This size will not correspond * to the ratio when we are doing things like 16:9 in a Flat frame. */ - Size _dcp_size; + libdcp::Size _dcp_size; /** id for use in metadata */ std::string _id; /** nickname (e.g. Flat, Scope) */ @@ -104,7 +104,7 @@ private: class FixedFormat : public Format { public: - FixedFormat (int, Size, std::string, std::string, std::string); + FixedFormat (int, libdcp::Size, std::string, std::string, std::string); int ratio_as_integer (boost::shared_ptr) const { return _ratio; @@ -125,7 +125,7 @@ private: class VariableFormat : public Format { public: - VariableFormat (Size, std::string, std::string, std::string); + VariableFormat (libdcp::Size, std::string, std::string, std::string); int ratio_as_integer (boost::shared_ptr f) const; float ratio_as_float (boost::shared_ptr f) const; diff --git a/src/lib/image.cc b/src/lib/image.cc index f774f476f..feda09ec5 100644 --- a/src/lib/image.cc +++ b/src/lib/image.cc @@ -95,7 +95,7 @@ Image::components () const } shared_ptr -Image::scale (Size out_size, Scaler const * scaler, bool aligned) const +Image::scale (libdcp::Size out_size, Scaler const * scaler, bool aligned) const { assert (scaler); @@ -124,11 +124,11 @@ Image::scale (Size out_size, Scaler const * scaler, bool aligned) const * @param scaler Scaler to use. */ shared_ptr -Image::scale_and_convert_to_rgb (Size out_size, int padding, Scaler const * scaler, bool aligned) const +Image::scale_and_convert_to_rgb (libdcp::Size out_size, int padding, Scaler const * scaler, bool aligned) const { assert (scaler); - Size content_size = out_size; + libdcp::Size content_size = out_size; content_size.width -= (padding * 2); shared_ptr rgb (new SimpleImage (PIX_FMT_RGB24, content_size, aligned)); @@ -215,7 +215,7 @@ Image::post_process (string pp, bool aligned) const shared_ptr Image::crop (Crop crop, bool aligned) const { - Size cropped_size = size (); + libdcp::Size cropped_size = size (); cropped_size.width -= crop.left + crop.right; cropped_size.height -= crop.top + crop.bottom; @@ -368,7 +368,7 @@ Image::bytes_per_pixel (int c) const * @param p Pixel format. * @param s Size in pixels. */ -SimpleImage::SimpleImage (AVPixelFormat p, Size s, bool aligned) +SimpleImage::SimpleImage (AVPixelFormat p, libdcp::Size s, bool aligned) : Image (p) , _size (s) , _aligned (aligned) @@ -466,7 +466,7 @@ SimpleImage::stride () const return _stride; } -Size +libdcp::Size SimpleImage::size () const { return _size; @@ -503,10 +503,10 @@ FilterBufferImage::stride () const return _buffer->linesize; } -Size +libdcp::Size FilterBufferImage::size () const { - return Size (_buffer->video->w, _buffer->video->h); + return libdcp::Size (_buffer->video->w, _buffer->video->h); } RGBPlusAlphaImage::RGBPlusAlphaImage (shared_ptr im) diff --git a/src/lib/image.h b/src/lib/image.h index e19c6f54b..adee8bc4d 100644 --- a/src/lib/image.h +++ b/src/lib/image.h @@ -65,14 +65,14 @@ public: /** @return Array of strides for each line (including any alignment padding bytes) */ virtual int * stride () const = 0; - /** @return Size of the image, in pixels */ - virtual Size size () const = 0; + /** @return libdcp::Size of the image, in pixels */ + virtual libdcp::Size size () const = 0; int components () const; int lines (int) const; - boost::shared_ptr scale_and_convert_to_rgb (Size out_size, int padding, Scaler const * scaler, bool aligned) const; - boost::shared_ptr scale (Size, Scaler const *, bool aligned) 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 (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); boost::shared_ptr crop (Crop c, bool aligned) const; @@ -106,7 +106,7 @@ public: uint8_t ** data () const; int * line_size () const; int * stride () const; - Size size () const; + libdcp::Size size () const; private: /* Not allowed */ @@ -122,7 +122,7 @@ private: class SimpleImage : public Image { public: - SimpleImage (AVPixelFormat, Size, bool); + SimpleImage (AVPixelFormat, libdcp::Size, bool); SimpleImage (SimpleImage const &); SimpleImage& operator= (SimpleImage const &); ~SimpleImage (); @@ -130,14 +130,14 @@ public: uint8_t ** data () const; int * line_size () const; int * stride () const; - Size size () const; + libdcp::Size size () const; protected: void allocate (); void swap (SimpleImage &); private: - Size _size; ///< size in pixels + libdcp::Size _size; ///< size in pixels uint8_t** _data; ///< array of pointers to components int* _line_size; ///< array of sizes of the data in each line, in pixels (without any alignment padding bytes) int* _stride; ///< array of strides for each line (including any alignment padding bytes) diff --git a/src/lib/imagemagick_decoder.cc b/src/lib/imagemagick_decoder.cc index bad1fb813..5ebd6c8e1 100644 --- a/src/lib/imagemagick_decoder.cc +++ b/src/lib/imagemagick_decoder.cc @@ -50,7 +50,7 @@ ImageMagickDecoder::ImageMagickDecoder ( _iter = _files.begin (); } -Size +libdcp::Size ImageMagickDecoder::native_size () const { if (_files.empty ()) { @@ -60,7 +60,7 @@ ImageMagickDecoder::native_size () const /* Look at the first file and assume its size holds for all */ using namespace MagickCore; Magick::Image* image = new Magick::Image (_film->content_path ()); - Size const s = Size (image->columns(), image->rows()); + libdcp::Size const s = libdcp::Size (image->columns(), image->rows()); delete image; return s; @@ -80,7 +80,7 @@ ImageMagickDecoder::pass () Magick::Image* magick_image = new Magick::Image (_film->content_path ()); - Size size = native_size (); + libdcp::Size size = native_size (); shared_ptr image (new SimpleImage (PIX_FMT_RGB24, size, false)); using namespace MagickCore; diff --git a/src/lib/imagemagick_decoder.h b/src/lib/imagemagick_decoder.h index 6f426f308..c4795b003 100644 --- a/src/lib/imagemagick_decoder.h +++ b/src/lib/imagemagick_decoder.h @@ -33,7 +33,7 @@ public: return 0; } - Size native_size () const; + libdcp::Size native_size () const; SourceFrame length () const { /* We don't know */ diff --git a/src/lib/make_dcp_job.cc b/src/lib/make_dcp_job.cc index b9f0cacf3..705521626 100644 --- a/src/lib/make_dcp_job.cc +++ b/src/lib/make_dcp_job.cc @@ -59,9 +59,9 @@ MakeDCPJob::name () const /** @param f DCP frame index */ string -MakeDCPJob::j2c_path (int f, int offset) const +MakeDCPJob::j2c_path (int f) const { - SourceFrame const s = ((f + offset) * dcp_frame_rate(_film->frames_per_second()).skip) + _film->dcp_trim_start(); + SourceFrame const s = (f * dcp_frame_rate(_film->frames_per_second()).skip) + _film->dcp_trim_start(); return _opt->frame_out_path (s, false); } @@ -107,71 +107,45 @@ MakeDCPJob::run () dcp.add_cpl (cpl); - int frames_per_reel = 0; - if (_film->reel_size()) { - frames_per_reel = (_film->reel_size().get() / (_film->j2k_bandwidth() / 8)) * dfr.frames_per_second; - } else { - frames_per_reel = frames; - } - - int frames_done = 0; - int reel = 0; - - while (frames_done < frames) { - - descend (float (frames_per_reel) / frames); - - int this_time = std::min (frames_per_reel, (frames - frames_done)); - - descend (0.8); - - shared_ptr pa ( - new libdcp::MonoPictureAsset ( - boost::bind (&MakeDCPJob::j2c_path, this, _1, frames_done), + descend (0.8); + + shared_ptr pa ( + new libdcp::MonoPictureAsset ( + boost::bind (&MakeDCPJob::j2c_path, this, _1), + _film->dir (_film->dcp_name()), + "video.mxf", + &dcp.Progress, + dfr.frames_per_second, + frames, + _opt->out_size + ) + ); + + ascend (); + + shared_ptr sa; + + if (_film->audio_channels() > 0) { + descend (0.1); + sa.reset ( + new libdcp::SoundAsset ( + boost::bind (&MakeDCPJob::wav_path, this, _1), _film->dir (_film->dcp_name()), - String::compose ("video_%1.mxf", reel), + "audio.mxf", &dcp.Progress, dfr.frames_per_second, - this_time, - _opt->out_size.width, - _opt->out_size.height + frames, + dcp_audio_channels (_film->audio_channels()) ) ); - - ascend (); - - shared_ptr sa; - - if (_film->audio_channels() > 0) { - descend (0.1); - sa.reset ( - new libdcp::SoundAsset ( - boost::bind (&MakeDCPJob::wav_path, this, _1), - _film->dir (_film->dcp_name()), - String::compose ("audio_%1.mxf", reel), - &dcp.Progress, - dfr.frames_per_second, - this_time, - frames_done, - dcp_audio_channels (_film->audio_channels()) - ) - ); - ascend (); - } - - descend (0.1); - cpl->add_reel (shared_ptr (new libdcp::Reel (pa, sa, shared_ptr ()))); - ascend (); - - frames_done += frames_per_reel; - ++reel; - ascend (); } + descend (0.05); + cpl->add_reel (shared_ptr (new libdcp::Reel (pa, sa, shared_ptr ()))); ascend (); - - descend (0.1); + + descend (0.05); dcp.write_xml (); ascend (); diff --git a/src/lib/make_dcp_job.h b/src/lib/make_dcp_job.h index 5e4f78a25..1aa906b0a 100644 --- a/src/lib/make_dcp_job.h +++ b/src/lib/make_dcp_job.h @@ -38,7 +38,7 @@ public: private: void dcp_progress (float); - std::string j2c_path (int, int) const; + std::string j2c_path (int) const; std::string wav_path (libdcp::Channel) const; boost::shared_ptr _opt; diff --git a/src/lib/matcher.h b/src/lib/matcher.h index b94c28446..60bb87432 100644 --- a/src/lib/matcher.h +++ b/src/lib/matcher.h @@ -35,6 +35,6 @@ private: int _video_frames; int64_t _audio_frames; boost::optional _pixel_format; - boost::optional _size; + boost::optional _size; boost::optional _channels; }; diff --git a/src/lib/options.h b/src/lib/options.h index 55b066a2d..2f2f44b64 100644 --- a/src/lib/options.h +++ b/src/lib/options.h @@ -90,7 +90,7 @@ public: return s.str (); } - Size out_size; ///< size of output images + libdcp::Size out_size; ///< size of output images int padding; ///< number of pixels of padding (in terms of the output size) each side of the image /** Range of video frames to encode (in DCP frames) */ diff --git a/src/lib/server.cc b/src/lib/server.cc index bea75cff8..1bb8f205e 100644 --- a/src/lib/server.cc +++ b/src/lib/server.cc @@ -92,9 +92,9 @@ Server::process (shared_ptr socket) return -1; } - Size in_size (get_required_int (kv, "input_width"), get_required_int (kv, "input_height")); + libdcp::Size in_size (get_required_int (kv, "input_width"), get_required_int (kv, "input_height")); int pixel_format_int = get_required_int (kv, "input_pixel_format"); - Size out_size (get_required_int (kv, "output_width"), get_required_int (kv, "output_height")); + libdcp::Size out_size (get_required_int (kv, "output_width"), get_required_int (kv, "output_height")); int padding = get_required_int (kv, "padding"); int subtitle_offset = get_required_int (kv, "subtitle_offset"); float subtitle_scale = get_required_float (kv, "subtitle_scale"); @@ -105,7 +105,7 @@ Server::process (shared_ptr socket) int colour_lut_index = get_required_int (kv, "colour_lut"); int j2k_bandwidth = get_required_int (kv, "j2k_bandwidth"); Position subtitle_position (get_optional_int (kv, "subtitle_x"), get_optional_int (kv, "subtitle_y")); - Size subtitle_size (get_optional_int (kv, "subtitle_width"), get_optional_int (kv, "subtitle_height")); + libdcp::Size subtitle_size (get_optional_int (kv, "subtitle_width"), get_optional_int (kv, "subtitle_height")); /* This checks that colour_lut_index is within range */ colour_lut_index_to_name (colour_lut_index); diff --git a/src/lib/subtitle.cc b/src/lib/subtitle.cc index c52d3ac66..8a9998d6a 100644 --- a/src/lib/subtitle.cc +++ b/src/lib/subtitle.cc @@ -55,7 +55,7 @@ TimedSubtitle::TimedSubtitle (AVSubtitle const & sub) throw DecodeError ("non-bitmap subtitles not yet supported"); } - shared_ptr image (new SimpleImage (PIX_FMT_RGBA, Size (rect->w, rect->h), true)); + shared_ptr image (new SimpleImage (PIX_FMT_RGBA, libdcp::Size (rect->w, rect->h), true)); /* Start of the first line in the subtitle */ uint8_t* sub_p = rect->pict.data[0]; diff --git a/src/lib/util.cc b/src/lib/util.cc index 0fced638c..7f370b896 100644 --- a/src/lib/util.cc +++ b/src/lib/util.cc @@ -244,7 +244,7 @@ dvdomatic_setup () * @return FFmpeg crop filter string. */ string -crop_string (Position start, Size size) +crop_string (Position start, libdcp::Size size) { stringstream s; s << "crop=" << size.width << ":" << size.height << ":" << start.x << ":" << start.y; @@ -377,17 +377,6 @@ dcp_audio_channels (int f) return f; } - -bool operator== (Size const & a, Size const & b) -{ - return (a.width == b.width && a.height == b.height); -} - -bool operator!= (Size const & a, Size const & b) -{ - return !(a == b); -} - bool operator== (Crop const & a, Crop const & b) { return (a.left == b.left && a.right == b.right && a.top == b.top && a.bottom == b.bottom); diff --git a/src/lib/util.h b/src/lib/util.h index 024c40fb5..77fb943e0 100644 --- a/src/lib/util.h +++ b/src/lib/util.h @@ -29,6 +29,7 @@ #include #include #include +#include extern "C" { #include #include @@ -78,33 +79,6 @@ enum ContentType { VIDEO ///< content is a video }; -/** @class Size - * @brief Representation of the size of something */ -struct Size -{ - /** Construct a zero Size */ - Size () - : width (0) - , height (0) - {} - - /** @param w Width. - * @param h Height. - */ - Size (int w, int h) - : width (w) - , height (h) - {} - - /** width */ - int width; - /** height */ - int height; -}; - -extern bool operator== (Size const & a, Size const & b); -extern bool operator!= (Size const & a, Size const & b); - /** @struct Crop * @brief A description of the crop of an image or video. */ @@ -174,14 +148,14 @@ struct Rect return Position (x, y); } - Size size () const { - return Size (width, height); + libdcp::Size size () const { + return libdcp::Size (width, height); } Rect intersection (Rect const & other) const; }; -extern std::string crop_string (Position, Size); +extern std::string crop_string (Position, libdcp::Size); extern int dcp_audio_sample_rate (int); extern DCPFrameRate dcp_frame_rate (float); extern int dcp_audio_channels (int); diff --git a/src/lib/video_decoder.h b/src/lib/video_decoder.h index 7726d2057..b18082c69 100644 --- a/src/lib/video_decoder.h +++ b/src/lib/video_decoder.h @@ -32,7 +32,7 @@ public: /** @return video frames per second, or 0 if unknown */ virtual float frames_per_second () const = 0; /** @return native size in pixels */ - virtual Size native_size () const = 0; + virtual libdcp::Size native_size () const = 0; /** @return length (in source video frames), according to our content's header */ virtual SourceFrame length () const = 0; diff --git a/src/wx/film_editor.cc b/src/wx/film_editor.cc index 17c40c83d..72f2d4807 100644 --- a/src/wx/film_editor.cc +++ b/src/wx/film_editor.cc @@ -149,17 +149,6 @@ FilmEditor::make_film_panel () _film_sizer->Add (s); } - _multiple_reels = new wxCheckBox (_film_panel, wxID_ANY, wxT ("Make multiple reels")); - _film_sizer->Add (_multiple_reels); - - { - wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL); - _reel_size = new wxSpinCtrl (_film_panel, wxID_ANY); - s->Add (_reel_size); - add_label_to_sizer (s, _film_panel, "Gb each"); - _film_sizer->Add (s); - } - _dcp_ab = new wxCheckBox (_film_panel, wxID_ANY, wxT ("A/B")); video_control (_dcp_ab); _film_sizer->Add (_dcp_ab, 1); @@ -180,8 +169,6 @@ FilmEditor::make_film_panel () for (vector::const_iterator i = ct.begin(); i != ct.end(); ++i) { _dcp_content_type->Append (std_to_wx ((*i)->pretty_name ())); } - - _reel_size->SetRange(1, 1000); } void @@ -204,8 +191,6 @@ FilmEditor::connect_to_widgets () _still_duration->Connect (wxID_ANY, wxEVT_COMMAND_SPINCTRL_UPDATED, wxCommandEventHandler (FilmEditor::still_duration_changed), 0, this); _dcp_trim_start->Connect (wxID_ANY, wxEVT_COMMAND_SPINCTRL_UPDATED, wxCommandEventHandler (FilmEditor::dcp_trim_start_changed), 0, this); _dcp_trim_end->Connect (wxID_ANY, wxEVT_COMMAND_SPINCTRL_UPDATED, wxCommandEventHandler (FilmEditor::dcp_trim_end_changed), 0, this); - _multiple_reels->Connect (wxID_ANY, wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler (FilmEditor::multiple_reels_toggled), 0, this); - _reel_size->Connect (wxID_ANY, wxEVT_COMMAND_SPINCTRL_UPDATED, wxCommandEventHandler (FilmEditor::reel_size_changed), 0, this); _with_subtitles->Connect (wxID_ANY, wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler (FilmEditor::with_subtitles_toggled), 0, this); _subtitle_offset->Connect (wxID_ANY, wxEVT_COMMAND_SPINCTRL_UPDATED, wxCommandEventHandler (FilmEditor::subtitle_offset_changed), 0, this); _subtitle_scale->Connect (wxID_ANY, wxEVT_COMMAND_SPINCTRL_UPDATED, wxCommandEventHandler (FilmEditor::subtitle_scale_changed), 0, this); @@ -478,32 +463,6 @@ FilmEditor::trust_content_header_changed (wxCommandEvent &) _film->set_trust_content_header (_trust_content_header->GetValue ()); } -void -FilmEditor::multiple_reels_toggled (wxCommandEvent &) -{ - if (!_film) { - return; - } - - if (_multiple_reels->GetValue()) { - _film->set_reel_size (_reel_size->GetValue() * 1e9); - } else { - _film->unset_reel_size (); - } - - setup_reel_control_sensitivity (); -} - -void -FilmEditor::reel_size_changed (wxCommandEvent &) -{ - if (!_film) { - return; - } - - _film->set_reel_size (static_cast (_reel_size->GetValue()) * 1e9); -} - /** Called when the DCP A/B switch has been toggled */ void FilmEditor::dcp_ab_toggled (wxCommandEvent &) @@ -681,15 +640,6 @@ FilmEditor::film_changed (Film::Property p) case Film::DCP_TRIM_END: checked_set (_dcp_trim_end, _film->dcp_trim_end()); break; - case Film::REEL_SIZE: - if (_film->reel_size()) { - checked_set (_multiple_reels, true); - checked_set (_reel_size, _film->reel_size().get() / 1e9); - } else { - checked_set (_multiple_reels, false); - } - setup_reel_control_sensitivity (); - break; case Film::AUDIO_GAIN: checked_set (_audio_gain, _film->audio_gain ()); break; @@ -813,7 +763,6 @@ FilmEditor::set_film (shared_ptr f) film_changed (Film::SCALER); film_changed (Film::DCP_TRIM_START); film_changed (Film::DCP_TRIM_END); - film_changed (Film::REEL_SIZE); film_changed (Film::DCP_AB); film_changed (Film::CONTENT_AUDIO_STREAM); film_changed (Film::EXTERNAL_AUDIO); @@ -858,8 +807,6 @@ FilmEditor::set_things_sensitive (bool s) _dcp_content_type->Enable (s); _dcp_trim_start->Enable (s); _dcp_trim_end->Enable (s); - _multiple_reels->Enable (s); - _reel_size->Enable (s); _dcp_ab->Enable (s); _colour_lut->Enable (s); _j2k_bandwidth->Enable (s); @@ -870,7 +817,6 @@ FilmEditor::set_things_sensitive (bool s) setup_subtitle_control_sensitivity (); setup_audio_control_sensitivity (); - setup_reel_control_sensitivity (); } /** Called when the `Edit filters' button has been clicked */ @@ -1211,9 +1157,3 @@ FilmEditor::external_audio_changed (wxCommandEvent &) _film->set_external_audio (a); } - -void -FilmEditor::setup_reel_control_sensitivity () -{ - _reel_size->Enable (_multiple_reels->GetValue ()); -} diff --git a/src/wx/film_editor.h b/src/wx/film_editor.h index 34e67eef1..8a900f1e4 100644 --- a/src/wx/film_editor.h +++ b/src/wx/film_editor.h @@ -65,8 +65,6 @@ private: void format_changed (wxCommandEvent &); void dcp_trim_start_changed (wxCommandEvent &); void dcp_trim_end_changed (wxCommandEvent &); - void multiple_reels_toggled (wxCommandEvent &); - void reel_size_changed (wxCommandEvent &); void dcp_content_type_changed (wxCommandEvent &); void dcp_ab_toggled (wxCommandEvent &); void scaler_changed (wxCommandEvent &); @@ -94,7 +92,6 @@ private: void setup_formats (); void setup_subtitle_control_sensitivity (); void setup_audio_control_sensitivity (); - void setup_reel_control_sensitivity (); void setup_streams (); void setup_audio_details (); @@ -170,8 +167,6 @@ private: wxSpinCtrl* _dcp_trim_start; wxSpinCtrl* _dcp_trim_end; - wxCheckBox* _multiple_reels; - wxSpinCtrl* _reel_size; /** Selector to generate an A/B comparison DCP */ wxCheckBox* _dcp_ab; diff --git a/src/wx/film_viewer.cc b/src/wx/film_viewer.cc index 3d8198457..e014a8731 100644 --- a/src/wx/film_viewer.cc +++ b/src/wx/film_viewer.cc @@ -257,13 +257,13 @@ FilmViewer::raw_to_display () return; } - Size old_size; + libdcp::Size old_size; if (_display_frame) { old_size = _display_frame->size(); } /* Get a compacted image as we have to feed it to wxWidgets */ - _display_frame = _raw_frame->scale_and_convert_to_rgb (Size (_out_width, _out_height), 0, _film->scaler(), false); + _display_frame = _raw_frame->scale_and_convert_to_rgb (libdcp::Size (_out_width, _out_height), 0, _film->scaler(), false); if (old_size != _display_frame->size()) { _clear_required = true; diff --git a/src/wx/film_viewer.h b/src/wx/film_viewer.h index 6029c04f3..c6b5e7c0c 100644 --- a/src/wx/film_viewer.h +++ b/src/wx/film_viewer.h @@ -59,7 +59,7 @@ private: boost::shared_ptr _film; - wxBoxSizer* _v_sizer; + wxSizer* _v_sizer; wxPanel* _panel; wxSlider* _slider; wxToggleButton* _play_button; diff --git a/test/test.cc b/test/test.cc index c393aac5e..5f6d687ac 100644 --- a/test/test.cc +++ b/test/test.cc @@ -325,7 +325,7 @@ do_remote_encode (shared_ptr frame, ServerDescription* descriptio BOOST_AUTO_TEST_CASE (client_server_test) { - shared_ptr image (new SimpleImage (PIX_FMT_RGB24, Size (1998, 1080), false)); + shared_ptr image (new SimpleImage (PIX_FMT_RGB24, libdcp::Size (1998, 1080), false)); uint8_t* p = image->data()[0]; for (int y = 0; y < 1080; ++y) { @@ -336,7 +336,7 @@ BOOST_AUTO_TEST_CASE (client_server_test) } } - shared_ptr sub_image (new SimpleImage (PIX_FMT_RGBA, Size (100, 200), false)); + shared_ptr sub_image (new SimpleImage (PIX_FMT_RGBA, libdcp::Size (100, 200), false)); p = sub_image->data()[0]; for (int y = 0; y < 200; ++y) { for (int x = 0; x < 100; ++x) { @@ -355,7 +355,7 @@ BOOST_AUTO_TEST_CASE (client_server_test) new DCPVideoFrame ( image, subtitle, - Size (1998, 1080), + libdcp::Size (1998, 1080), 0, 0, 1, @@ -531,7 +531,7 @@ BOOST_AUTO_TEST_CASE (job_manager_test) BOOST_AUTO_TEST_CASE (compact_image_test) { - SimpleImage* s = new SimpleImage (PIX_FMT_RGB24, Size (50, 50), false); + SimpleImage* s = new SimpleImage (PIX_FMT_RGB24, libdcp::Size (50, 50), false); BOOST_CHECK_EQUAL (s->components(), 1); BOOST_CHECK_EQUAL (s->stride()[0], 50 * 3); BOOST_CHECK_EQUAL (s->line_size()[0], 50 * 3); @@ -557,7 +557,7 @@ BOOST_AUTO_TEST_CASE (compact_image_test) BOOST_CHECK (t->stride()[0] == s->stride()[0]); /* assignment operator */ - SimpleImage* u = new SimpleImage (PIX_FMT_YUV422P, Size (150, 150), true); + SimpleImage* u = new SimpleImage (PIX_FMT_YUV422P, libdcp::Size (150, 150), true); *u = *s; BOOST_CHECK_EQUAL (u->components(), 1); BOOST_CHECK_EQUAL (u->stride()[0], 50 * 3); @@ -580,7 +580,7 @@ BOOST_AUTO_TEST_CASE (compact_image_test) BOOST_AUTO_TEST_CASE (aligned_image_test) { - SimpleImage* s = new SimpleImage (PIX_FMT_RGB24, Size (50, 50), true); + SimpleImage* s = new SimpleImage (PIX_FMT_RGB24, libdcp::Size (50, 50), true); BOOST_CHECK_EQUAL (s->components(), 1); /* 160 is 150 aligned to the nearest 32 bytes */ BOOST_CHECK_EQUAL (s->stride()[0], 160); @@ -607,7 +607,7 @@ BOOST_AUTO_TEST_CASE (aligned_image_test) BOOST_CHECK (t->stride()[0] == s->stride()[0]); /* assignment operator */ - SimpleImage* u = new SimpleImage (PIX_FMT_YUV422P, Size (150, 150), false); + SimpleImage* u = new SimpleImage (PIX_FMT_YUV422P, libdcp::Size (150, 150), false); *u = *s; BOOST_CHECK_EQUAL (u->components(), 1); BOOST_CHECK_EQUAL (u->stride()[0], 160); -- cgit v1.2.3 From dc08d2da6bf14fd469005ea3512992c66b041da9 Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Wed, 20 Feb 2013 11:51:12 +0000 Subject: Fix servomatic build. Hopefully resolve confusion wrt linesize and stride for FilterBufferImage; the linesize can apparently sometimes be (slightly) larger than the width for byte-per-pixel images (e.g. YUV420P). Remove grotty peek-style socket communication and use a hopefully more robust send of the length of data as a binary word before the data itself. Should fix #62. --- src/lib/dcp_video_frame.cc | 22 +++----- src/lib/image.cc | 19 +++++-- src/lib/image.h | 1 + src/lib/server.cc | 10 ++-- src/lib/util.cc | 128 ++++++++++---------------------------------- src/lib/util.h | 22 ++++---- src/tools/servomatictest.cc | 52 ++++++++++++------ src/tools/wscript | 2 +- 8 files changed, 104 insertions(+), 152 deletions(-) (limited to 'src/lib/server.cc') diff --git a/src/lib/dcp_video_frame.cc b/src/lib/dcp_video_frame.cc index 4f3fda44a..9b96724b0 100644 --- a/src/lib/dcp_video_frame.cc +++ b/src/lib/dcp_video_frame.cc @@ -316,7 +316,7 @@ DCPVideoFrame::encode_remotely (ServerDescription const * serv) shared_ptr socket (new Socket); - socket->connect (*endpoint_iterator, 30); + socket->connect (*endpoint_iterator); stringstream s; s << "encode please\n" @@ -352,21 +352,17 @@ DCPVideoFrame::encode_remotely (ServerDescription const * serv) _input->lines(0), _input->lines(1), _input->lines(2), _input->line_size()[0], _input->line_size()[1], _input->line_size()[2] )); - - socket->write ((uint8_t *) s.str().c_str(), s.str().length() + 1, 30); + + 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); } - char buffer[32]; - socket->read_indefinite ((uint8_t *) buffer, sizeof (buffer), 30); - socket->consume (strlen (buffer) + 1); - shared_ptr e (new RemotelyEncodedData (atoi (buffer))); - - /* now read the rest */ - socket->read_definite_and_consume (e->data(), e->size(), 30); + shared_ptr e (new RemotelyEncodedData (socket->read_uint32 ())); + socket->read (e->data(), e->size()); _log->log (String::compose ("Finished remotely-encoded frame %1", _frame)); @@ -438,10 +434,8 @@ EncodedData::write_info (shared_ptr film, int frame, libdcp::FrameIn void EncodedData::send (shared_ptr socket) { - stringstream s; - s << _size; - socket->write ((uint8_t *) s.str().c_str(), s.str().length() + 1, 30); - socket->write (_data, _size, 30); + socket->write (_size); + socket->write (_data, _size); } LocallyEncodedData::LocallyEncodedData (uint8_t* d, int s) diff --git a/src/lib/image.cc b/src/lib/image.cc index 0ec6bd26c..73d499fe8 100644 --- a/src/lib/image.cc +++ b/src/lib/image.cc @@ -323,7 +323,7 @@ Image::read_from_socket (shared_ptr socket) for (int i = 0; i < components(); ++i) { uint8_t* p = data()[i]; for (int y = 0; y < lines(i); ++y) { - socket->read_definite_and_consume (p, line_size()[i], 30); + socket->read (p, line_size()[i]); p += stride()[i]; } } @@ -335,7 +335,7 @@ Image::write_to_socket (shared_ptr socket) const for (int i = 0; i < components(); ++i) { uint8_t* p = data()[i]; for (int y = 0; y < lines(i); ++y) { - socket->write (p, line_size()[i], 30); + socket->write (p, line_size()[i]); p += stride()[i]; } } @@ -503,12 +503,18 @@ FilterBufferImage::FilterBufferImage (AVPixelFormat p, AVFilterBufferRef* b) : Image (p) , _buffer (b) { - + _line_size = (int *) av_malloc (4 * sizeof (int)); + _line_size[0] = _line_size[1] = _line_size[2] = _line_size[3] = 0; + + for (int i = 0; i < components(); ++i) { + _line_size[i] = size().width * bytes_per_pixel(i); + } } FilterBufferImage::~FilterBufferImage () { avfilter_unref_buffer (_buffer); + av_free (_line_size); } uint8_t ** @@ -520,13 +526,16 @@ FilterBufferImage::data () const int * FilterBufferImage::line_size () const { - return _buffer->linesize; + return _line_size; } int * FilterBufferImage::stride () const { - /* XXX? */ + /* I've seen images where the _buffer->linesize is larger than the width + (by a small amount), suggesting that _buffer->linesize is what we call + stride. But I'm not sure. + */ return _buffer->linesize; } diff --git a/src/lib/image.h b/src/lib/image.h index 23f13a648..f40ea9280 100644 --- a/src/lib/image.h +++ b/src/lib/image.h @@ -117,6 +117,7 @@ private: FilterBufferImage& operator= (FilterBufferImage const &); AVFilterBufferRef* _buffer; + int* _line_size; }; /** @class SimpleImage diff --git a/src/lib/server.cc b/src/lib/server.cc index d75ab0fb6..3614ed9e4 100644 --- a/src/lib/server.cc +++ b/src/lib/server.cc @@ -28,6 +28,7 @@ #include #include #include +#include #include "server.h" #include "util.h" #include "scaler.h" @@ -45,6 +46,7 @@ using boost::algorithm::is_any_of; using boost::algorithm::split; using boost::thread; using boost::bind; +using boost::scoped_array; using libdcp::Size; /** Create a server description from a string of metadata returned from as_metadata(). @@ -82,11 +84,11 @@ Server::Server (Log* log) int Server::process (shared_ptr socket) { - char buffer[512]; - socket->read_indefinite ((uint8_t *) buffer, sizeof (buffer), 30); - socket->consume (strlen (buffer) + 1); + uint32_t length = socket->read_uint32 (); + scoped_array buffer (new char[length]); + socket->read (reinterpret_cast (buffer.get()), length); - stringstream s (buffer); + stringstream s (buffer.get()); multimap kv = read_key_value (s); if (get_required_string (kv, "encode") != "please") { diff --git a/src/lib/util.cc b/src/lib/util.cc index c0c8be984..4ee304600 100644 --- a/src/lib/util.cc +++ b/src/lib/util.cc @@ -485,10 +485,10 @@ colour_lut_index_to_name (int index) return ""; } -Socket::Socket () +Socket::Socket (int timeout) : _deadline (_io_service) , _socket (_io_service) - , _buffer_data (0) + , _timeout (timeout) { _deadline.expires_at (posix_time::pos_infin); check (); @@ -505,14 +505,13 @@ Socket::check () _deadline.async_wait (boost::bind (&Socket::check, this)); } -/** Blocking connect with timeout. +/** Blocking connect. * @param endpoint End-point to connect to. - * @param timeout Time-out in seconds. */ void -Socket::connect (asio::ip::basic_resolver_entry const & endpoint, int timeout) +Socket::connect (asio::ip::basic_resolver_entry const & endpoint) { - _deadline.expires_from_now (posix_time::seconds (timeout)); + _deadline.expires_from_now (posix_time::seconds (_timeout)); system::error_code ec = asio::error::would_block; _socket.async_connect (endpoint, lambda::var(ec) = lambda::_1); do { @@ -524,132 +523,61 @@ Socket::connect (asio::ip::basic_resolver_entry const & endpoint, } } -/** Blocking write with timeout. +/** Blocking write. * @param data Buffer to write. * @param size Number of bytes to write. - * @param timeout Time-out, in seconds. */ void -Socket::write (uint8_t const * data, int size, int timeout) +Socket::write (uint8_t const * data, int size) { - _deadline.expires_from_now (posix_time::seconds (timeout)); + _deadline.expires_from_now (posix_time::seconds (_timeout)); system::error_code ec = asio::error::would_block; asio::async_write (_socket, asio::buffer (data, size), lambda::var(ec) = lambda::_1); + do { _io_service.run_one (); } while (ec == asio::error::would_block); if (ec) { - throw NetworkError ("write timed out"); + throw NetworkError (ec.message ()); } } -/** Blocking read with timeout. +void +Socket::write (uint32_t v) +{ + v = htonl (v); + write (reinterpret_cast (&v), 4); +} + +/** Blocking read. * @param data Buffer to read to. * @param size Number of bytes to read. - * @param timeout Time-out, in seconds. */ -int -Socket::read (uint8_t* data, int size, int timeout) +void +Socket::read (uint8_t* data, int size) { - _deadline.expires_from_now (posix_time::seconds (timeout)); + _deadline.expires_from_now (posix_time::seconds (_timeout)); system::error_code ec = asio::error::would_block; - int amount_read = 0; - - _socket.async_read_some ( - asio::buffer (data, size), - (lambda::var(ec) = lambda::_1, lambda::var(amount_read) = lambda::_2) - ); + asio::async_read (_socket, asio::buffer (data, size), lambda::var(ec) = lambda::_1); do { _io_service.run_one (); } while (ec == asio::error::would_block); if (ec) { - amount_read = 0; - } - - return amount_read; -} - -/** Mark some data as being `consumed', so that it will not be returned - * as data again. - * @param size Amount of data to consume, in bytes. - */ -void -Socket::consume (int size) -{ - assert (_buffer_data >= size); - - _buffer_data -= size; - if (_buffer_data > 0) { - /* Shift still-valid data to the start of the buffer */ - memmove (_buffer, _buffer + size, _buffer_data); + throw NetworkError (ec.message ()); } } -/** Read a definite amount of data from our socket, and mark - * it as consumed. - * @param data Where to put the data. - * @param size Number of bytes to read. - */ -void -Socket::read_definite_and_consume (uint8_t* data, int size, int timeout) -{ - int const from_buffer = min (_buffer_data, size); - if (from_buffer > 0) { - /* Get data from our buffer */ - memcpy (data, _buffer, from_buffer); - consume (from_buffer); - /* Update our output state */ - data += from_buffer; - size -= from_buffer; - } - - /* read() the rest */ - while (size > 0) { - int const n = read (data, size, timeout); - if (n <= 0) { - throw NetworkError ("could not read"); - } - - data += n; - size -= n; - } -} - -/** Read as much data as is available, up to some limit. - * @param data Where to put the data. - * @param size Maximum amount of data to read. - * - * XXX This method assumes that there is always lots of data to read(); - * if there isn't, it will hang waiting for data that will never arrive. - */ -void -Socket::read_indefinite (uint8_t* data, int size, int timeout) +uint32_t +Socket::read_uint32 () { - assert (size < int (sizeof (_buffer))); - - /* Amount of extra data we need to read () */ - int to_read = size - _buffer_data; - while (to_read > 0) { - /* read as much of it as we can (into our buffer) */ - int const n = read (_buffer + _buffer_data, to_read, timeout); - if (n <= 0) { - throw NetworkError ("could not read"); - } - - to_read -= n; - _buffer_data += n; - } - - assert (_buffer_data >= size); - - /* copy data into the output buffer */ - assert (size >= _buffer_data); - memcpy (data, _buffer, size); + uint32_t v; + read (reinterpret_cast (&v), 4); + return ntohl (v); } /** @param other A Rect. diff --git a/src/lib/util.h b/src/lib/util.h index c4940a5d7..87735ea8e 100644 --- a/src/lib/util.h +++ b/src/lib/util.h @@ -194,39 +194,35 @@ extern std::string get_optional_string (std::multimap * that are useful for DVD-o-matic. * * This class wraps some things that I could not work out how to do with boost; - * most notably, sync read/write calls with timeouts, and the ability to peek into - * data being read. + * most notably, sync read/write calls with timeouts. */ class Socket { public: - Socket (); + Socket (int timeout = 30); /** @return Our underlying socket */ boost::asio::ip::tcp::socket& socket () { return _socket; } - void connect (boost::asio::ip::basic_resolver_entry const & endpoint, int timeout); - void write (uint8_t const * data, int size, int timeout); + void connect (boost::asio::ip::basic_resolver_entry const & endpoint); + + void write (uint32_t n); + void write (uint8_t const * data, int size); - void read_definite_and_consume (uint8_t* data, int size, int timeout); - void read_indefinite (uint8_t* data, int size, int timeout); - void consume (int amount); + void read (uint8_t* data, int size); + uint32_t read_uint32 (); private: void check (); - int read (uint8_t* data, int size, int timeout); Socket (Socket const &); boost::asio::io_service _io_service; boost::asio::deadline_timer _deadline; boost::asio::ip::tcp::socket _socket; - /** a buffer for small reads */ - uint8_t _buffer[1024]; - /** amount of valid data in the buffer */ - int _buffer_data; + int _timeout; }; /** @class AudioBuffers diff --git a/src/tools/servomatictest.cc b/src/tools/servomatictest.cc index 88c2a833e..91ad02120 100644 --- a/src/tools/servomatictest.cc +++ b/src/tools/servomatictest.cc @@ -34,22 +34,40 @@ #include "scaler.h" #include "log.h" #include "decoder_factory.h" +#include "video_decoder.h" -using namespace std; -using namespace boost; +using std::cout; +using std::cerr; +using std::string; +using std::pair; +using boost::shared_ptr; -static Server* server; -static Log log_ ("servomatictest.log"); +static ServerDescription* server; +static FileLog log_ ("servomatictest.log"); +static int frame = 0; void -process_video (shared_ptr image, bool, int frame) +process_video (shared_ptr image, bool, shared_ptr sub) { - shared_ptr local (new DCPVideoFrame (image, Size (1024, 1024), 0, Scaler::from_id ("bicubic"), frame, 24, "", 0, 250000000, &log_)); - shared_ptr remote (new DCPVideoFrame (image, Size (1024, 1024), 0, Scaler::from_id ("bicubic"), frame, 24, "", 0, 250000000, &log_)); + shared_ptr local ( + new DCPVideoFrame ( + image, sub, + libdcp::Size (1024, 1024), 0, 0, 0, + Scaler::from_id ("bicubic"), frame, 24, "", 0, 250000000, &log_) + ); + + shared_ptr remote ( + new DCPVideoFrame ( + image, sub, + libdcp::Size (1024, 1024), 0, 0, 0, + Scaler::from_id ("bicubic"), frame, 24, "", 0, 250000000, &log_) + ); cout << "Frame " << frame << ": "; cout.flush (); + ++frame; + shared_ptr local_encoded = local->encode_locally (); shared_ptr remote_encoded; @@ -130,17 +148,21 @@ main (int argc, char* argv[]) dvdomatic_setup (); - server = new Server (server_host, 1); - Film film (film_dir, true); + server = new ServerDescription (server_host, 1); + shared_ptr film (new Film (film_dir, true)); - shared_ptr opt (new Options ("fred", "jim", "sheila")); - opt->out_size = Size (1024, 1024); - opt->decode_audio = false; + DecodeOptions opt; + opt.decode_audio = false; + opt.decode_subtitles = true; + opt.video_sync = true; - shared_ptr decoder = decoder_factory (film.state_copy(), opt, 0, &log_); + Decoders decoders = decoder_factory (film, opt); try { - decoder->Video.connect (sigc::ptr_fun (process_video)); - decoder->go (); + decoders.video->Video.connect (boost::bind (process_video, _1, _2, _3)); + bool done = false; + while (!done) { + done = decoders.video->pass (); + } } catch (std::exception& e) { cerr << "Error: " << e.what() << "\n"; } diff --git a/src/tools/wscript b/src/tools/wscript index 5a837f845..c843c61d8 100644 --- a/src/tools/wscript +++ b/src/tools/wscript @@ -1,5 +1,5 @@ def build(bld): - for t in ['makedcp', 'servomatic_cli']: + for t in ['makedcp', 'servomatic_cli', 'servomatictest']: obj = bld(features = 'cxx cxxprogram') obj.uselib = 'BOOST_THREAD OPENJPEG DCP AVFORMAT AVFILTER AVCODEC AVUTIL SWSCALE POSTPROC' obj.includes = ['..'] -- cgit v1.2.3 From 0d3f5aae5b99832b7c5d55f32f5bccb365caa3fd Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Thu, 28 Feb 2013 22:20:07 +0000 Subject: Various markup and tweaks. --- TRANSLATORS | 2 +- i18n.py | 10 +- run/dvdomatic | 3 + src/lib/ab_transcode_job.cc | 4 +- src/lib/config.cc | 54 ++++---- src/lib/dci_metadata.cc | 30 ++-- src/lib/dcp_content_type.cc | 22 +-- src/lib/dcp_video_frame.cc | 62 +++++---- src/lib/decoder.cc | 6 +- src/lib/dolby_cp750.cc | 4 +- src/lib/encoder.cc | 44 +++--- src/lib/examine_content_job.cc | 10 +- src/lib/external_audio_decoder.cc | 12 +- src/lib/ffmpeg_compatibility.cc | 10 +- src/lib/ffmpeg_decoder.cc | 50 +++---- src/lib/film.cc | 284 +++++++++++++++++++------------------- src/lib/filter.cc | 54 ++++---- src/lib/filter_graph.cc | 48 ++++--- src/lib/format.cc | 35 ++--- src/lib/image.cc | 8 +- src/lib/imagemagick_decoder.cc | 4 +- src/lib/job.cc | 23 +-- src/lib/log.cc | 12 +- src/lib/matcher.cc | 10 +- src/lib/scaler.cc | 20 +-- src/lib/scp_dcp_job.cc | 36 ++--- src/lib/server.cc | 44 +++--- src/lib/stream.cc | 4 +- src/lib/subtitle.cc | 6 +- src/lib/timer.cc | 10 +- src/lib/transcode_job.cc | 14 +- src/lib/util.cc | 80 ++++++----- src/lib/video_decoder.cc | 4 +- src/lib/writer.cc | 28 ++-- src/tools/dvdomatic.cc | 10 +- src/wx/config_dialog.cc | 4 +- src/wx/film_editor.cc | 23 ++- src/wx/film_viewer.cc | 2 +- src/wx/properties_dialog.cc | 2 +- src/wx/server_dialog.cc | 2 +- wscript | 4 +- 41 files changed, 580 insertions(+), 514 deletions(-) (limited to 'src/lib/server.cc') diff --git a/TRANSLATORS b/TRANSLATORS index cbfc875d4..625b03613 100644 --- a/TRANSLATORS +++ b/TRANSLATORS @@ -1,7 +1,7 @@ Translating DVD-o-matic ----------------------- -1. Run ./waf po +1. Run ./waf pot This will generate build/src/lib/dvdomatic.pot and build/src/wx/libdvdomatic-wx.pot. diff --git a/i18n.py b/i18n.py index 10eaa38e9..c22cbdb95 100644 --- a/i18n.py +++ b/i18n.py @@ -2,15 +2,19 @@ import glob import os from waflib import Logs -def pot(dir, sources, name): +def pot(dir, sources, name, all = False): s = "" for f in sources.split('\n'): t = f.strip() if len(t) > 0: s += (os.path.join(dir, t)) + " " - Logs.info('Making %s.pot' % os.path.join('build', dir, name)) - os.system('xgettext -d %s -s --keyword=_ -p %s -o %s.pot %s' % (name, os.path.join('build', dir), name, s)) + if all: + Logs.info('Making %s.pot (extracting all)' % os.path.join('build', dir, name)) + os.system('xgettext -d %s -s --extract-all -p %s -o %s.pot %s' % (name, os.path.join('build', dir), name, s)) + else: + Logs.info('Making %s.pot' % os.path.join('build', dir, name)) + os.system('xgettext -d %s -s --keyword=_ --add-comments=/ -p %s -o %s.pot %s' % (name, os.path.join('build', dir), name, s)) def po_to_mo(dir, name): diff --git a/run/dvdomatic b/run/dvdomatic index ff3897064..31fd09fb9 100755 --- a/run/dvdomatic +++ b/run/dvdomatic @@ -7,6 +7,9 @@ if [ "$1" == "--debug" ]; then elif [ "$1" == "--valgrind" ]; then shift valgrind --tool="memcheck" build/src/tools/dvdomatic $* +elif [ "$1" == "--i18n" ]; then + shift + LANG=fr_FR.UTF8 build/src/tools/dvdomatic "$*" else build/src/tools/dvdomatic "$*" fi diff --git a/src/lib/ab_transcode_job.cc b/src/lib/ab_transcode_job.cc index 025c23c86..4ffdd9af6 100644 --- a/src/lib/ab_transcode_job.cc +++ b/src/lib/ab_transcode_job.cc @@ -26,6 +26,8 @@ #include "config.h" #include "encoder.h" +#include "i18n.h" + using std::string; using boost::shared_ptr; @@ -44,7 +46,7 @@ ABTranscodeJob::ABTranscodeJob (shared_ptr f, DecodeOptions o) string ABTranscodeJob::name () const { - return String::compose ("A/B transcode %1", _film->name()); + return String::compose (_("A/B transcode %1"), _film->name()); } void diff --git a/src/lib/config.cc b/src/lib/config.cc index c165859b0..82a31b3cf 100644 --- a/src/lib/config.cc +++ b/src/lib/config.cc @@ -28,6 +28,8 @@ #include "filter.h" #include "sound_processor.h" +#include "i18n.h" + using std::vector; using std::ifstream; using std::string; @@ -40,9 +42,9 @@ Config* Config::_instance = 0; Config::Config () : _num_local_encoding_threads (2) , _server_port (6192) - , _reference_scaler (Scaler::from_id ("bicubic")) - , _tms_path (".") - , _sound_processor (SoundProcessor::from_id ("dolby_cp750")) + , _reference_scaler (Scaler::from_id (N_("bicubic"))) + , _tms_path (N_(".")) + , _sound_processor (SoundProcessor::from_id (N_("dolby_cp750"))) { _allowed_dcp_frame_rates.push_back (24); _allowed_dcp_frame_rates.push_back (25); @@ -67,27 +69,27 @@ Config::Config () string const k = line.substr (0, s); string const v = line.substr (s + 1); - if (k == "num_local_encoding_threads") { + if (k == N_("num_local_encoding_threads")) { _num_local_encoding_threads = atoi (v.c_str ()); - } else if (k == "default_directory") { + } else if (k == N_("default_directory")) { _default_directory = v; - } else if (k == "server_port") { + } else if (k == N_("server_port")) { _server_port = atoi (v.c_str ()); - } else if (k == "reference_scaler") { + } else if (k == N_("reference_scaler")) { _reference_scaler = Scaler::from_id (v); - } else if (k == "reference_filter") { + } else if (k == N_("reference_filter")) { _reference_filters.push_back (Filter::from_id (v)); - } else if (k == "server") { + } else if (k == N_("server")) { _servers.push_back (ServerDescription::create_from_metadata (v)); - } else if (k == "tms_ip") { + } else if (k == N_("tms_ip")) { _tms_ip = v; - } else if (k == "tms_path") { + } else if (k == N_("tms_path")) { _tms_path = v; - } else if (k == "tms_user") { + } else if (k == N_("tms_user")) { _tms_user = v; - } else if (k == "tms_password") { + } else if (k == N_("tms_password")) { _tms_password = v; - } else if (k == "sound_processor") { + } else if (k == N_("sound_processor")) { _sound_processor = SoundProcessor::from_id (v); } @@ -101,7 +103,7 @@ Config::file () const { boost::filesystem::path p; p /= g_get_user_config_dir (); - p /= ".dvdomatic"; + p /= N_(".dvdomatic"); return p.string (); } @@ -121,24 +123,24 @@ void Config::write () const { ofstream f (file().c_str ()); - f << "num_local_encoding_threads " << _num_local_encoding_threads << "\n" - << "default_directory " << _default_directory << "\n" - << "server_port " << _server_port << "\n" - << "reference_scaler " << _reference_scaler->id () << "\n"; + f << N_("num_local_encoding_threads ") << _num_local_encoding_threads << N_("\n") + << N_("default_directory ") << _default_directory << N_("\n") + << N_("server_port ") << _server_port << N_("\n") + << N_("reference_scaler ") << _reference_scaler->id () << N_("\n"); for (vector::const_iterator i = _reference_filters.begin(); i != _reference_filters.end(); ++i) { - f << "reference_filter " << (*i)->id () << "\n"; + f << N_("reference_filter ") << (*i)->id () << N_("\n"); } for (vector::const_iterator i = _servers.begin(); i != _servers.end(); ++i) { - f << "server " << (*i)->as_metadata () << "\n"; + f << N_("server ") << (*i)->as_metadata () << N_("\n"); } - f << "tms_ip " << _tms_ip << "\n"; - f << "tms_path " << _tms_path << "\n"; - f << "tms_user " << _tms_user << "\n"; - f << "tms_password " << _tms_password << "\n"; - f << "sound_processor " << _sound_processor->id () << "\n"; + f << N_("tms_ip ") << _tms_ip << N_("\n"); + f << N_("tms_path ") << _tms_path << N_("\n"); + f << N_("tms_user ") << _tms_user << N_("\n"); + f << N_("tms_password ") << _tms_password << N_("\n"); + f << N_("sound_processor ") << _sound_processor->id () << N_("\n"); _default_dci_metadata.write (f); } diff --git a/src/lib/dci_metadata.cc b/src/lib/dci_metadata.cc index 2b4cc3ae7..758886db4 100644 --- a/src/lib/dci_metadata.cc +++ b/src/lib/dci_metadata.cc @@ -20,36 +20,38 @@ #include #include "dci_metadata.h" +#include "i18n.h" + using namespace std; void DCIMetadata::write (ostream& f) const { - f << "audio_language " << audio_language << "\n"; - f << "subtitle_language " << subtitle_language << "\n"; - f << "territory " << territory << "\n"; - f << "rating " << rating << "\n"; - f << "studio " << studio << "\n"; - f << "facility " << facility << "\n"; - f << "package_type " << package_type << "\n"; + f << N_("audio_language ") << audio_language << N_("\n"); + f << N_("subtitle_language ") << subtitle_language << N_("\n"); + f << N_("territory ") << territory << N_("\n"); + f << N_("rating ") << rating << N_("\n"); + f << N_("studio ") << studio << N_("\n"); + f << N_("facility ") << facility << N_("\n"); + f << N_("package_type ") << package_type << N_("\n"); } void DCIMetadata::read (string k, string v) { - if (k == "audio_language") { + if (k == N_("audio_language")) { audio_language = v; - } else if (k == "subtitle_language") { + } else if (k == N_("subtitle_language")) { subtitle_language = v; - } else if (k == "territory") { + } else if (k == N_("territory")) { territory = v; - } else if (k == "rating") { + } else if (k == N_("rating")) { rating = v; - } else if (k == "studio") { + } else if (k == N_("studio")) { studio = v; - } else if (k == "facility") { + } else if (k == N_("facility")) { facility = v; - } else if (k == "package_type") { + } else if (k == N_("package_type")) { package_type = v; } } diff --git a/src/lib/dcp_content_type.cc b/src/lib/dcp_content_type.cc index 1c96979e4..82bd5fa01 100644 --- a/src/lib/dcp_content_type.cc +++ b/src/lib/dcp_content_type.cc @@ -24,6 +24,8 @@ #include #include "dcp_content_type.h" +#include "i18n.h" + using namespace std; vector DCPContentType::_dcp_content_types; @@ -39,16 +41,16 @@ DCPContentType::DCPContentType (string p, libdcp::ContentKind k, string d) void DCPContentType::setup_dcp_content_types () { - _dcp_content_types.push_back (new DCPContentType ("Feature", libdcp::FEATURE, "FTR")); - _dcp_content_types.push_back (new DCPContentType ("Short", libdcp::SHORT, "SHR")); - _dcp_content_types.push_back (new DCPContentType ("Trailer", libdcp::TRAILER, "TLR")); - _dcp_content_types.push_back (new DCPContentType ("Test", libdcp::TEST, "TST")); - _dcp_content_types.push_back (new DCPContentType ("Transitional", libdcp::TRANSITIONAL, "XSN")); - _dcp_content_types.push_back (new DCPContentType ("Rating", libdcp::RATING, "RTG")); - _dcp_content_types.push_back (new DCPContentType ("Teaser", libdcp::TEASER, "TSR")); - _dcp_content_types.push_back (new DCPContentType ("Policy", libdcp::POLICY, "POL")); - _dcp_content_types.push_back (new DCPContentType ("Public Service Announcement", libdcp::PUBLIC_SERVICE_ANNOUNCEMENT, "PSA")); - _dcp_content_types.push_back (new DCPContentType ("Advertisement", libdcp::ADVERTISEMENT, "ADV")); + _dcp_content_types.push_back (new DCPContentType (_("Feature"), libdcp::FEATURE, N_("FTR"))); + _dcp_content_types.push_back (new DCPContentType (_("Short"), libdcp::SHORT, N_("SHR"))); + _dcp_content_types.push_back (new DCPContentType (_("Trailer"), libdcp::TRAILER, N_("TLR"))); + _dcp_content_types.push_back (new DCPContentType (_("Test"), libdcp::TEST, N_("TST"))); + _dcp_content_types.push_back (new DCPContentType (_("Transitional"), libdcp::TRANSITIONAL, N_("XSN"))); + _dcp_content_types.push_back (new DCPContentType (_("Rating"), libdcp::RATING, N_("RTG"))); + _dcp_content_types.push_back (new DCPContentType (_("Teaser"), libdcp::TEASER, N_("TSR"))); + _dcp_content_types.push_back (new DCPContentType (_("Policy"), libdcp::POLICY, N_("POL"))); + _dcp_content_types.push_back (new DCPContentType (_("Public Service Announcement"), libdcp::PUBLIC_SERVICE_ANNOUNCEMENT, N_("PSA"))); + _dcp_content_types.push_back (new DCPContentType (_("Advertisement"), libdcp::ADVERTISEMENT, N_("ADV"))); } DCPContentType const * diff --git a/src/lib/dcp_video_frame.cc b/src/lib/dcp_video_frame.cc index 9b96724b0..098d222cd 100644 --- a/src/lib/dcp_video_frame.cc +++ b/src/lib/dcp_video_frame.cc @@ -56,6 +56,8 @@ #include "log.h" #include "subtitle.h" +#include "i18n.h" + using std::string; using std::stringstream; using std::ofstream; @@ -119,7 +121,7 @@ DCPVideoFrame::create_openjpeg_container () _image = opj_image_create (3, &_cmptparm[0], CLRSPC_SRGB); if (_image == 0) { - throw EncodeError ("could not create libopenjpeg image"); + throw EncodeError (N_("could not create libopenjpeg image")); } _image->x0 = 0; @@ -265,7 +267,7 @@ DCPVideoFrame::encode_locally () _parameters->tcp_numlayers++; _parameters->cp_disto_alloc = 1; _parameters->cp_rsiz = CINEMA2K; - _parameters->cp_comment = strdup ("DVD-o-matic"); + _parameters->cp_comment = strdup (N_("DVD-o-matic")); _parameters->cp_cinema = CINEMA2K_24; /* 3 components, so use MCT */ @@ -278,7 +280,7 @@ DCPVideoFrame::encode_locally () /* get a J2K compressor handle */ _cinfo = opj_create_compress (CODEC_J2K); if (_cinfo == 0) { - throw EncodeError ("could not create JPEG2000 encoder"); + throw EncodeError (N_("could not create JPEG2000 encoder")); } /* Set event manager to null (openjpeg 1.3 bug) */ @@ -289,15 +291,15 @@ DCPVideoFrame::encode_locally () _cio = opj_cio_open ((opj_common_ptr) _cinfo, 0, 0); if (_cio == 0) { - throw EncodeError ("could not open JPEG2000 stream"); + throw EncodeError (N_("could not open JPEG2000 stream")); } int const r = opj_encode (_cinfo, _cio, _image, 0); if (r == 0) { - throw EncodeError ("JPEG2000 encoding failed"); + throw EncodeError (N_("JPEG2000 encoding failed")); } - _log->log (String::compose ("Finished locally-encoded frame %1", _frame)); + _log->log (String::compose (N_("Finished locally-encoded frame %1"), _frame)); return shared_ptr (new LocallyEncodedData (_cio->buffer, cio_tell (_cio))); } @@ -319,35 +321,35 @@ DCPVideoFrame::encode_remotely (ServerDescription const * serv) socket->connect (*endpoint_iterator); stringstream s; - s << "encode please\n" - << "input_width " << _input->size().width << "\n" - << "input_height " << _input->size().height << "\n" - << "input_pixel_format " << _input->pixel_format() << "\n" - << "output_width " << _out_size.width << "\n" - << "output_height " << _out_size.height << "\n" - << "padding " << _padding << "\n" - << "subtitle_offset " << _subtitle_offset << "\n" - << "subtitle_scale " << _subtitle_scale << "\n" - << "scaler " << _scaler->id () << "\n" - << "frame " << _frame << "\n" - << "frames_per_second " << _frames_per_second << "\n"; + 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_("frame ") << _frame << N_("\n") + << N_("frames_per_second ") << _frames_per_second << N_("\n"); if (!_post_process.empty()) { - s << "post_process " << _post_process << "\n"; + s << N_("post_process ") << _post_process << N_("\n"); } - s << "colour_lut " << _colour_lut << "\n" - << "j2k_bandwidth " << _j2k_bandwidth << "\n"; + s << N_("colour_lut ") << _colour_lut << N_("\n") + << N_("j2k_bandwidth ") << _j2k_bandwidth << N_("\n"); if (_subtitle) { - s << "subtitle_x " << _subtitle->position().x << "\n" - << "subtitle_y " << _subtitle->position().y << "\n" - << "subtitle_width " << _subtitle->image()->size().width << "\n" - << "subtitle_height " << _subtitle->image()->size().height << "\n"; + 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 ( - "Sending to remote; pixel format %1, components %2, lines (%3,%4,%5), line sizes (%6,%7,%8)", + 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] @@ -364,7 +366,7 @@ DCPVideoFrame::encode_remotely (ServerDescription const * serv) shared_ptr e (new RemotelyEncodedData (socket->read_uint32 ())); socket->read (e->data(), e->size()); - _log->log (String::compose ("Finished remotely-encoded frame %1", _frame)); + _log->log (String::compose (N_("Finished remotely-encoded frame %1"), _frame)); return e; } @@ -381,9 +383,9 @@ EncodedData::EncodedData (string file) _size = boost::filesystem::file_size (file); _data = new uint8_t[_size]; - FILE* f = fopen (file.c_str(), "rb"); + FILE* f = fopen (file.c_str(), N_("rb")); if (!f) { - throw FileError ("could not open file for reading", file); + throw FileError (_("could not open file for reading"), file); } fread (_data, 1, _size, f); @@ -405,7 +407,7 @@ EncodedData::write (shared_ptr film, int frame) const { string const tmp_j2c = film->j2c_path (frame, true); - FILE* f = fopen (tmp_j2c.c_str (), "wb"); + FILE* f = fopen (tmp_j2c.c_str (), N_("wb")); if (!f) { throw WriteFileError (tmp_j2c, errno); diff --git a/src/lib/decoder.cc b/src/lib/decoder.cc index 30009460f..52b22fa06 100644 --- a/src/lib/decoder.cc +++ b/src/lib/decoder.cc @@ -36,6 +36,8 @@ #include "subtitle.h" #include "filter_graph.h" +#include "i18n.h" + using std::string; using std::stringstream; using std::min; @@ -60,7 +62,7 @@ Decoder::Decoder (boost::shared_ptr f, DecodeOptions o) bool Decoder::seek (double) { - throw DecodeError ("decoder does not support seek"); + throw DecodeError (N_("decoder does not support seek")); } /** Seek so that the next frame we will produce is the same as the last one. @@ -69,5 +71,5 @@ Decoder::seek (double) bool Decoder::seek_to_last () { - throw DecodeError ("decoder does not support seek"); + throw DecodeError (N_("decoder does not support seek")); } diff --git a/src/lib/dolby_cp750.cc b/src/lib/dolby_cp750.cc index 262e57bc7..b45e62b87 100644 --- a/src/lib/dolby_cp750.cc +++ b/src/lib/dolby_cp750.cc @@ -19,10 +19,12 @@ #include "dolby_cp750.h" +#include "i18n.h" + using namespace std; DolbyCP750::DolbyCP750 () - : SoundProcessor ("dolby_cp750", "Dolby CP750") + : SoundProcessor ("dolby_cp750", _("Dolby CP750")) { } diff --git a/src/lib/encoder.cc b/src/lib/encoder.cc index f25256379..d4a27d01b 100644 --- a/src/lib/encoder.cc +++ b/src/lib/encoder.cc @@ -39,6 +39,8 @@ #include "cross.h" #include "writer.h" +#include "i18n.h" + using std::pair; using std::string; using std::stringstream; @@ -79,7 +81,7 @@ Encoder::process_begin () #ifdef HAVE_SWRESAMPLE stringstream s; - s << "Will resample audio from " << _film->audio_stream()->sample_rate() << " to " << _film->target_audio_sample_rate(); + s << String::compose (N_("Will resample audio from %1 to %2"), _film->audio_stream()->sample_rate(), _film->target_audio_sample_rate()); _film->log()->log (s.str ()); /* We will be using planar float data when we call the resampler */ @@ -96,7 +98,7 @@ Encoder::process_begin () swr_init (_swr_context); #else - throw EncodeError ("Cannot resample audio as libswresample is not present"); + throw EncodeError (_("Cannot resample audio as libswresample is not present")); #endif } else { #ifdef HAVE_SWRESAMPLE @@ -132,7 +134,7 @@ Encoder::process_end () int const frames = swr_convert (_swr_context, (uint8_t **) out->data(), 256, 0, 0); if (frames < 0) { - throw EncodeError ("could not run sample-rate converter"); + throw EncodeError (_("could not run sample-rate converter")); } if (frames == 0) { @@ -149,11 +151,11 @@ Encoder::process_end () boost::mutex::scoped_lock lock (_mutex); - _film->log()->log ("Clearing queue of " + lexical_cast (_queue.size ())); + _film->log()->log (String::compose (N_("Clearing queue of %1"), _queue.size ())); /* Keep waking workers until the queue is empty */ while (!_queue.empty ()) { - _film->log()->log ("Waking with " + lexical_cast (_queue.size ()), Log::VERBOSE); + _film->log()->log (String::compose (N_("Waking with %1"), _queue.size ()), Log::VERBOSE); _condition.notify_all (); _condition.wait (lock); } @@ -162,7 +164,7 @@ Encoder::process_end () terminate_threads (); - _film->log()->log ("Mopping up " + lexical_cast (_queue.size())); + _film->log()->log (String::compose (N_("Mopping up %1"), _queue.size())); /* The following sequence of events can occur in the above code: 1. a remote worker takes the last image off the queue @@ -174,12 +176,12 @@ Encoder::process_end () */ for (list >::iterator i = _queue.begin(); i != _queue.end(); ++i) { - _film->log()->log (String::compose ("Encode left-over frame %1", (*i)->frame ())); + _film->log()->log (String::compose (N_("Encode left-over frame %1"), (*i)->frame ())); try { _writer->write ((*i)->encode_locally(), (*i)->frame ()); frame_done (); } catch (std::exception& e) { - _film->log()->log (String::compose ("Local encode failed (%1)", e.what ())); + _film->log()->log (String::compose (N_("Local encode failed (%1)"), e.what ())); } } @@ -242,9 +244,9 @@ Encoder::process_video (shared_ptr image, bool same, boost::shared_ptr= _threads.size() * 2 && !_terminate) { - TIMING ("decoder sleeps with queue of %1", _queue.size()); + TIMING (_("decoder sleeps with queue of %1"), _queue.size()); _condition.wait (lock); - TIMING ("decoder wakes with queue of %1", _queue.size()); + TIMING (_("decoder wakes with queue of %1"), _queue.size()); } if (_terminate) { @@ -266,7 +268,7 @@ Encoder::process_video (shared_ptr image, bool same, boost::shared_ptr const s = Filter::ffmpeg_strings (_film->filters()); - TIMING ("adding to queue of %1", _queue.size ()); + TIMING (_("adding to queue of %1"), _queue.size ()); _queue.push_back (boost::shared_ptr ( new DCPVideoFrame ( image, sub, _film->format()->dcp_size(), _film->format()->dcp_padding (_film), @@ -309,7 +311,7 @@ Encoder::process_audio (shared_ptr data) ); if (resampled_frames < 0) { - throw EncodeError ("could not run sample-rate converter"); + throw EncodeError (_("could not run sample-rate converter")); } resampled->set_frames (resampled_frames); @@ -347,7 +349,7 @@ Encoder::encoder_thread (ServerDescription* server) while (1) { - TIMING ("encoder thread %1 sleeps", boost::this_thread::get_id()); + TIMING (N_("encoder thread %1 sleeps"), boost::this_thread::get_id()); boost::mutex::scoped_lock lock (_mutex); while (_queue.empty () && !_terminate) { _condition.wait (lock); @@ -357,9 +359,9 @@ Encoder::encoder_thread (ServerDescription* server) return; } - TIMING ("encoder thread %1 wakes with queue of %2", boost::this_thread::get_id(), _queue.size()); + TIMING (N_("encoder thread %1 wakes with queue of %2"), boost::this_thread::get_id(), _queue.size()); boost::shared_ptr vf = _queue.front (); - _film->log()->log (String::compose ("Encoder thread %1 pops frame %2 from queue", boost::this_thread::get_id(), vf->frame()), Log::VERBOSE); + _film->log()->log (String::compose (N_("Encoder thread %1 pops frame %2 from queue"), boost::this_thread::get_id(), vf->frame()), Log::VERBOSE); _queue.pop_front (); lock.unlock (); @@ -371,7 +373,7 @@ Encoder::encoder_thread (ServerDescription* server) encoded = vf->encode_remotely (server); if (remote_backoff > 0) { - _film->log()->log (String::compose ("%1 was lost, but now she is found; removing backoff", server->host_name ())); + _film->log()->log (String::compose (N_("%1 was lost, but now she is found; removing backoff"), server->host_name ())); } /* This job succeeded, so remove any backoff */ @@ -384,18 +386,18 @@ Encoder::encoder_thread (ServerDescription* server) } _film->log()->log ( String::compose ( - "Remote encode of %1 on %2 failed (%3); thread sleeping for %4s", + N_("Remote encode of %1 on %2 failed (%3); thread sleeping for %4s"), vf->frame(), server->host_name(), e.what(), remote_backoff) ); } } else { try { - TIMING ("encoder thread %1 begins local encode of %2", boost::this_thread::get_id(), vf->frame()); + TIMING (N_("encoder thread %1 begins local encode of %2"), boost::this_thread::get_id(), vf->frame()); encoded = vf->encode_locally (); - TIMING ("encoder thread %1 finishes local encode of %2", boost::this_thread::get_id(), vf->frame()); + TIMING (N_("encoder thread %1 finishes local encode of %2"), boost::this_thread::get_id(), vf->frame()); } catch (std::exception& e) { - _film->log()->log (String::compose ("Local encode failed (%1)", e.what ())); + _film->log()->log (String::compose (N_("Local encode failed (%1)"), e.what ())); } } @@ -405,7 +407,7 @@ Encoder::encoder_thread (ServerDescription* server) } else { lock.lock (); _film->log()->log ( - String::compose ("Encoder thread %1 pushes frame %2 back onto queue after failure", boost::this_thread::get_id(), vf->frame()) + String::compose (N_("Encoder thread %1 pushes frame %2 back onto queue after failure"), boost::this_thread::get_id(), vf->frame()) ); _queue.push_front (vf); lock.unlock (); diff --git a/src/lib/examine_content_job.cc b/src/lib/examine_content_job.cc index 31d76c4f7..4b30c9431 100644 --- a/src/lib/examine_content_job.cc +++ b/src/lib/examine_content_job.cc @@ -31,6 +31,8 @@ #include "film.h" #include "video_decoder.h" +#include "i18n.h" + using std::string; using std::vector; using std::pair; @@ -50,10 +52,10 @@ string ExamineContentJob::name () const { if (_film->name().empty ()) { - return "Examine content"; + return _("Examine content"); } - return String::compose ("Examine content of %1", _film->name()); + return String::compose (_("Examine content of %1"), _film->name()); } void @@ -90,7 +92,7 @@ ExamineContentJob::run () _film->set_length (decoders.video->video_frame()); - _film->log()->log (String::compose ("Video length examined as %1 frames", _film->length().get())); + _film->log()->log (String::compose (N_("Video length examined as %1 frames"), _film->length().get())); } else { @@ -99,7 +101,7 @@ ExamineContentJob::run () Decoders d = decoder_factory (_film, DecodeOptions()); _film->set_length (d.video->length()); - _film->log()->log (String::compose ("Video length obtained from header as %1 frames", _film->length().get())); + _film->log()->log (String::compose (N_("Video length obtained from header as %1 frames"), _film->length().get())); } ascend (); diff --git a/src/lib/external_audio_decoder.cc b/src/lib/external_audio_decoder.cc index 9c01bfb34..1248b5a3b 100644 --- a/src/lib/external_audio_decoder.cc +++ b/src/lib/external_audio_decoder.cc @@ -23,6 +23,8 @@ #include "film.h" #include "exceptions.h" +#include "i18n.h" + using std::vector; using std::string; using std::stringstream; @@ -67,11 +69,11 @@ ExternalAudioDecoder::open_files (sf_count_t & frames) SF_INFO info; SNDFILE* s = sf_open (files[i].c_str(), SFM_READ, &info); if (!s) { - throw DecodeError ("could not open external audio file for reading"); + throw DecodeError (_("could not open external audio file for reading")); } if (info.channels != 1) { - throw DecodeError ("external audio files must be mono"); + throw DecodeError (_("external audio files must be mono")); } sndfiles.push_back (s); @@ -89,7 +91,7 @@ ExternalAudioDecoder::open_files (sf_count_t & frames) first = false; } else { if (info.frames != frames) { - throw DecodeError ("external audio files have differing lengths"); + throw DecodeError (_("external audio files have differing lengths")); } } } @@ -158,7 +160,7 @@ ExternalAudioStream::create (string t, optional v) stringstream s (t); string type; s >> type; - if (type != "external") { + if (type != N_("external")) { return shared_ptr (); } @@ -182,5 +184,5 @@ ExternalAudioStream::ExternalAudioStream () string ExternalAudioStream::to_string () const { - return String::compose ("external %1 %2", _sample_rate, _channel_layout); + return String::compose (N_("external %1 %2"), _sample_rate, _channel_layout); } diff --git a/src/lib/ffmpeg_compatibility.cc b/src/lib/ffmpeg_compatibility.cc index 09f9276ac..361fa7423 100644 --- a/src/lib/ffmpeg_compatibility.cc +++ b/src/lib/ffmpeg_compatibility.cc @@ -22,6 +22,8 @@ extern "C" { } #include "exceptions.h" +#include "i18n.h" + #if LIBAVFILTER_VERSION_MAJOR == 2 && LIBAVFILTER_VERSION_MINOR == 15 typedef struct { @@ -67,13 +69,13 @@ get_sink () #if LIBAVFILTER_VERSION_MAJOR == 2 && LIBAVFILTER_VERSION_MINOR == 15 /* XXX does this leak stuff? */ AVFilter* buffer_sink = new AVFilter; - buffer_sink->name = av_strdup ("avsink"); + buffer_sink->name = av_strdup (N_("avsink")); buffer_sink->priv_size = sizeof (AVSinkContext); buffer_sink->init = avsink_init; buffer_sink->query_formats = avsink_query_formats; buffer_sink->inputs = new AVFilterPad[2]; AVFilterPad* i0 = const_cast (&buffer_sink->inputs[0]); - i0->name = "default"; + i0->name = N_("default"); i0->type = AVMEDIA_TYPE_VIDEO; i0->min_perms = AV_PERM_READ; i0->rej_perms = 0; @@ -91,9 +93,9 @@ get_sink () const_cast (&buffer_sink->outputs[0])->name = 0; return buffer_sink; #else - AVFilter* buffer_sink = avfilter_get_by_name("buffersink"); + AVFilter* buffer_sink = avfilter_get_by_name(N_("buffersink")); if (buffer_sink == 0) { - throw DecodeError ("Could not create buffer sink filter"); + throw DecodeError (N_("Could not create buffer sink filter")); } return buffer_sink; diff --git a/src/lib/ffmpeg_decoder.cc b/src/lib/ffmpeg_decoder.cc index d4ed76e37..8834f28ed 100644 --- a/src/lib/ffmpeg_decoder.cc +++ b/src/lib/ffmpeg_decoder.cc @@ -50,6 +50,8 @@ extern "C" { #include "filter_graph.h" #include "subtitle.h" +#include "i18n.h" + using std::cout; using std::string; using std::vector; @@ -113,7 +115,7 @@ FFmpegDecoder::setup_general () } if (avformat_find_stream_info (_format_context, 0) < 0) { - throw DecodeError ("could not find stream information"); + throw DecodeError (_("could not find stream information")); } /* Find video, audio and subtitle streams and choose the first of each */ @@ -148,12 +150,12 @@ FFmpegDecoder::setup_general () } if (_video_stream < 0) { - throw DecodeError ("could not find video stream"); + throw DecodeError (N_("could not find video stream")); } _frame = avcodec_alloc_frame (); if (_frame == 0) { - throw DecodeError ("could not allocate frame"); + throw DecodeError (N_("could not allocate frame")); } } @@ -164,11 +166,11 @@ FFmpegDecoder::setup_video () _video_codec = avcodec_find_decoder (_video_codec_context->codec_id); if (_video_codec == 0) { - throw DecodeError ("could not find video decoder"); + throw DecodeError (_("could not find video decoder")); } if (avcodec_open2 (_video_codec_context, _video_codec, 0) < 0) { - throw DecodeError ("could not open video decoder"); + throw DecodeError (N_("could not open video decoder")); } } @@ -186,11 +188,11 @@ FFmpegDecoder::setup_audio () _audio_codec = avcodec_find_decoder (_audio_codec_context->codec_id); if (_audio_codec == 0) { - throw DecodeError ("could not find audio decoder"); + throw DecodeError (_("could not find audio decoder")); } if (avcodec_open2 (_audio_codec_context, _audio_codec, 0) < 0) { - throw DecodeError ("could not open audio decoder"); + throw DecodeError (N_("could not open audio decoder")); } } @@ -205,11 +207,11 @@ FFmpegDecoder::setup_subtitle () _subtitle_codec = avcodec_find_decoder (_subtitle_codec_context->codec_id); if (_subtitle_codec == 0) { - throw DecodeError ("could not find subtitle decoder"); + throw DecodeError (_("could not find subtitle decoder")); } if (avcodec_open2 (_subtitle_codec_context, _subtitle_codec, 0) < 0) { - throw DecodeError ("could not open subtitle decoder"); + throw DecodeError (N_("could not open subtitle decoder")); } } @@ -224,7 +226,7 @@ FFmpegDecoder::pass () /* Maybe we should fail here, but for now we'll just finish off instead */ char buf[256]; av_strerror (r, buf, sizeof(buf)); - _film->log()->log (String::compose ("error on av_read_frame (%1) (%2)", buf, r)); + _film->log()->log (String::compose (N_("error on av_read_frame (%1) (%2)"), buf, r)); } /* Get any remaining frames */ @@ -265,7 +267,7 @@ FFmpegDecoder::pass () if (r >= 0 && frame_finished) { if (r != _packet.size) { - _film->log()->log (String::compose ("Used only %1 bytes of %2 in packet", r, _packet.size)); + _film->log()->log (String::compose (N_("Used only %1 bytes of %2 in packet"), r, _packet.size)); } if (_opt.video_sync) { @@ -303,7 +305,7 @@ FFmpegDecoder::pass () _film->log()->log ( String::compose ( - "First video at %1, first audio at %2, pushing %3 audio frames of silence for %4 channels (%5 bytes per sample)", + N_("First video at %1, first audio at %2, pushing %3 audio frames of silence for %4 channels (%5 bytes per sample)"), _first_video.get(), _first_audio.get(), s, ffa->channels(), bytes_per_audio_sample() ) ); @@ -443,7 +445,7 @@ FFmpegDecoder::deinterleave_audio (uint8_t** data, int size) break; default: - throw DecodeError (String::compose ("Unrecognised audio sample format (%1)", static_cast (audio_sample_format()))); + throw DecodeError (String::compose (_("Unrecognised audio sample format (%1)"), static_cast (audio_sample_format()))); } return audio; @@ -512,21 +514,21 @@ FFmpegDecoder::stream_name (AVStream* s) const { stringstream n; - AVDictionaryEntry const * lang = av_dict_get (s->metadata, "language", 0, 0); + AVDictionaryEntry const * lang = av_dict_get (s->metadata, N_("language"), 0, 0); if (lang) { n << lang->value; } - AVDictionaryEntry const * title = av_dict_get (s->metadata, "title", 0, 0); + AVDictionaryEntry const * title = av_dict_get (s->metadata, N_("title"), 0, 0); if (title) { if (!n.str().empty()) { - n << " "; + n << N_(" "); } n << title->value; } if (n.str().empty()) { - n << "unknown"; + n << N_("unknown"); } return n.str (); @@ -568,7 +570,7 @@ FFmpegDecoder::filter_and_emit_video (AVFrame* frame) if (i == _filter_graphs.end ()) { graph.reset (new FilterGraph (_film, this, libdcp::Size (frame->width, frame->height), (AVPixelFormat) frame->format)); _filter_graphs.push_back (graph); - _film->log()->log (String::compose ("New graph for %1x%2, pixel format %3", frame->width, frame->height, frame->format)); + _film->log()->log (String::compose (N_("New graph for %1x%2, pixel format %3"), frame->width, frame->height, frame->format)); } else { graph = *i; } @@ -622,7 +624,7 @@ FFmpegAudioStream::create (string t, optional v) stringstream s (t); string type; s >> type; - if (type != "ffmpeg") { + if (type != N_("ffmpeg")) { return shared_ptr (); } @@ -644,7 +646,7 @@ FFmpegAudioStream::FFmpegAudioStream (string t, optional version) string type; /* Current (marked version 1) */ n >> type >> _id >> _sample_rate >> _channel_layout; - assert (type == "ffmpeg"); + assert (type == N_("ffmpeg")); } for (int i = 0; i < name_index; ++i) { @@ -660,7 +662,7 @@ FFmpegAudioStream::FFmpegAudioStream (string t, optional version) string FFmpegAudioStream::to_string () const { - return String::compose ("ffmpeg %1 %2 %3 %4", _id, _sample_rate, _channel_layout, _name); + return String::compose (N_("ffmpeg %1 %2 %3 %4"), _id, _sample_rate, _channel_layout, _name); } void @@ -674,7 +676,7 @@ FFmpegDecoder::out_with_sync () * av_frame_get_best_effort_timestamp(_frame); _film->log()->log ( - String::compose ("Source video frame ready; source at %1, output at %2", source_pts_seconds, out_pts_seconds), + String::compose (N_("Source video frame ready; source at %1, output at %2"), source_pts_seconds, out_pts_seconds), Log::VERBOSE ); @@ -693,7 +695,7 @@ FFmpegDecoder::out_with_sync () repeat_last_video (); _film->log()->log ( String::compose ( - "Extra video frame inserted at %1s; source frame %2, source PTS %3 (at %4 fps)", + N_("Extra video frame inserted at %1s; source frame %2, source PTS %3 (at %4 fps)"), out_pts_seconds, video_frame(), source_pts_seconds, frames_per_second() ) ); @@ -705,7 +707,7 @@ FFmpegDecoder::out_with_sync () filter_and_emit_video (_frame); } else { /* Otherwise we are omitting a frame to keep things right */ - _film->log()->log (String::compose ("Frame removed at %1s", out_pts_seconds)); + _film->log()->log (String::compose (N_("Frame removed at %1s"), out_pts_seconds)); } } diff --git a/src/lib/film.cc b/src/lib/film.cc index addaa0852..c119f1515 100644 --- a/src/lib/film.cc +++ b/src/lib/film.cc @@ -88,7 +88,7 @@ Film::Film (string d, bool must_exist) , _trust_content_header (true) , _dcp_content_type (0) , _format (0) - , _scaler (Scaler::from_id ("bicubic")) + , _scaler (Scaler::from_id (N_("bicubic"))) , _trim_start (0) , _trim_end (0) , _dcp_ab (false) @@ -114,13 +114,13 @@ Film::Film (string d, bool must_exist) boost::filesystem::path p (boost::filesystem::system_complete (d)); boost::filesystem::path result; for (boost::filesystem::path::iterator i = p.begin(); i != p.end(); ++i) { - if (*i == "..") { - if (boost::filesystem::is_symlink (result) || result.filename() == "..") { + if (*i == N_("..")) { + if (boost::filesystem::is_symlink (result) || result.filename() == N_("..")) { result /= *i; } else { result = result.parent_path (); } - } else if (*i != ".") { + } else if (*i != N_(".")) { result /= *i; } } @@ -141,7 +141,7 @@ Film::Film (string d, bool must_exist) read_metadata (); } - _log = new FileLog (file ("log")); + _log = new FileLog (file (N_("log"))); } Film::Film (Film const & o) @@ -201,16 +201,16 @@ Film::video_state_identifier () const stringstream s; s << format()->id() - << "_" << content_digest() - << "_" << crop().left << "_" << crop().right << "_" << crop().top << "_" << crop().bottom - << "_" << f.first << "_" << f.second - << "_" << scaler()->id() - << "_" << j2k_bandwidth() - << "_" << boost::lexical_cast (colour_lut()); + << N_("_") << content_digest() + << N_("_") << crop().left << N_("_") << crop().right << N_("_") << crop().top << N_("_") << crop().bottom + << N_("_") << f.first << N_("_") << f.second + << N_("_") << scaler()->id() + << N_("_") << j2k_bandwidth() + << N_("_") << boost::lexical_cast (colour_lut()); if (dcp_ab()) { pair fa = Filter::ffmpeg_strings (Config::instance()->reference_filters()); - s << "ab_" << Config::instance()->reference_scaler()->id() << "_" << fa.first << "_" << fa.second; + s << N_("ab_") << Config::instance()->reference_scaler()->id() << N_("_") << fa.first << N_("_") << fa.second; } return s.str (); @@ -221,7 +221,7 @@ string Film::info_dir () const { boost::filesystem::path p; - p /= "info"; + p /= N_("info"); p /= video_state_identifier (); return dir (p.string()); } @@ -230,13 +230,13 @@ string Film::video_mxf_dir () const { boost::filesystem::path p; - return dir ("video"); + return dir (N_("video")); } string Film::video_mxf_filename () const { - return video_state_identifier() + ".mxf"; + return video_state_identifier() + N_(".mxf"); } /** Add suitable Jobs to the JobManager to create a DCP for this Film */ @@ -245,52 +245,52 @@ Film::make_dcp () { set_dci_date_today (); - if (dcp_name().find ("/") != string::npos) { - throw BadSettingError ("name", _("cannot contain slashes")); + if (dcp_name().find (N_("/")) != string::npos) { + throw BadSettingError (_("name"), _("cannot contain slashes")); } - log()->log (String::compose ("DVD-o-matic %1 git %2 using %3", dvdomatic_version, dvdomatic_git_commit, dependency_version_summary())); + log()->log (String::compose (N_("DVD-o-matic %1 git %2 using %3"), dvdomatic_version, dvdomatic_git_commit, dependency_version_summary())); { char buffer[128]; gethostname (buffer, sizeof (buffer)); - log()->log (String::compose ("Starting to make DCP on %1", buffer)); + log()->log (String::compose (N_("Starting to make DCP on %1"), buffer)); } - log()->log (String::compose ("Content is %1; type %2", content_path(), (content_type() == STILL ? "still" : "video"))); + log()->log (String::compose (N_("Content is %1; type %2"), content_path(), (content_type() == STILL ? _("still") : _("video")))); if (length()) { - log()->log (String::compose ("Content length %1", length().get())); + log()->log (String::compose (N_("Content length %1"), length().get())); } - log()->log (String::compose ("Content digest %1", content_digest())); - log()->log (String::compose ("%1 threads", Config::instance()->num_local_encoding_threads())); - log()->log (String::compose ("J2K bandwidth %1", j2k_bandwidth())); + log()->log (String::compose (N_("Content digest %1"), content_digest())); + log()->log (String::compose (N_("%1 threads"), Config::instance()->num_local_encoding_threads())); + log()->log (String::compose (N_("J2K bandwidth %1"), j2k_bandwidth())); #ifdef DVDOMATIC_DEBUG - log()->log ("DVD-o-matic built in debug mode."); + log()->log (N_("DVD-o-matic built in debug mode.")); #else - log()->log ("DVD-o-matic built in optimised mode."); + log()->log (N_("DVD-o-matic built in optimised mode.")); #endif #ifdef LIBDCP_DEBUG - log()->log ("libdcp built in debug mode."); + log()->log (N_("libdcp built in debug mode.")); #else - log()->log ("libdcp built in optimised mode."); + log()->log (N_("libdcp built in optimised mode.")); #endif pair const c = cpu_info (); - log()->log (String::compose ("CPU: %1, %2 processors", c.first, c.second)); + log()->log (String::compose (N_("CPU: %1, %2 processors"), c.first, c.second)); if (format() == 0) { - throw MissingSettingError ("format"); + throw MissingSettingError (_("format")); } if (content().empty ()) { - throw MissingSettingError ("content"); + throw MissingSettingError (_("content")); } if (dcp_content_type() == 0) { - throw MissingSettingError ("content type"); + throw MissingSettingError (_("content type")); } if (name().empty()) { - throw MissingSettingError ("name"); + throw MissingSettingError (_("name")); } DecodeOptions od; @@ -359,73 +359,73 @@ Film::write_metadata () const boost::filesystem::create_directories (directory()); - string const m = file ("metadata"); + string const m = file (N_("metadata")); ofstream f (m.c_str ()); if (!f.good ()) { throw CreateFileError (m); } - f << "version " << state_version << "\n"; + f << N_("version ") << state_version << N_("\n"); /* User stuff */ - f << "name " << _name << "\n"; - f << "use_dci_name " << _use_dci_name << "\n"; - f << "content " << _content << "\n"; - f << "trust_content_header " << (_trust_content_header ? "1" : "0") << "\n"; + f << N_("name ") << _name << N_("\n"); + f << N_("use_dci_name ") << _use_dci_name << N_("\n"); + f << N_("content ") << _content << N_("\n"); + f << N_("trust_content_header ") << (_trust_content_header ? N_("1") : N_("0")) << N_("\n"); if (_dcp_content_type) { - f << "dcp_content_type " << _dcp_content_type->dci_name () << "\n"; + f << N_("dcp_content_type ") << _dcp_content_type->dci_name () << N_("\n"); } if (_format) { - f << "format " << _format->as_metadata () << "\n"; + f << N_("format ") << _format->as_metadata () << N_("\n"); } - f << "left_crop " << _crop.left << "\n"; - f << "right_crop " << _crop.right << "\n"; - f << "top_crop " << _crop.top << "\n"; - f << "bottom_crop " << _crop.bottom << "\n"; + f << N_("left_crop ") << _crop.left << N_("\n"); + f << N_("right_crop ") << _crop.right << N_("\n"); + f << N_("top_crop ") << _crop.top << N_("\n"); + f << N_("bottom_crop ") << _crop.bottom << N_("\n"); for (vector::const_iterator i = _filters.begin(); i != _filters.end(); ++i) { - f << "filter " << (*i)->id () << "\n"; + f << N_("filter ") << (*i)->id () << N_("\n"); } - f << "scaler " << _scaler->id () << "\n"; - f << "trim_start " << _trim_start << "\n"; - f << "trim_end " << _trim_end << "\n"; - f << "dcp_ab " << (_dcp_ab ? "1" : "0") << "\n"; + f << N_("scaler ") << _scaler->id () << N_("\n"); + f << N_("trim_start ") << _trim_start << N_("\n"); + f << N_("trim_end ") << _trim_end << N_("\n"); + f << N_("dcp_ab ") << (_dcp_ab ? N_("1") : N_("0")) << N_("\n"); if (_content_audio_stream) { - f << "selected_content_audio_stream " << _content_audio_stream->to_string() << "\n"; + f << N_("selected_content_audio_stream ") << _content_audio_stream->to_string() << N_("\n"); } for (vector::const_iterator i = _external_audio.begin(); i != _external_audio.end(); ++i) { - f << "external_audio " << *i << "\n"; + f << N_("external_audio ") << *i << N_("\n"); } - f << "use_content_audio " << (_use_content_audio ? "1" : "0") << "\n"; - f << "audio_gain " << _audio_gain << "\n"; - f << "audio_delay " << _audio_delay << "\n"; - f << "still_duration " << _still_duration << "\n"; + f << N_("use_content_audio ") << (_use_content_audio ? N_("1") : N_("0")) << N_("\n"); + f << N_("audio_gain ") << _audio_gain << N_("\n"); + f << N_("audio_delay ") << _audio_delay << N_("\n"); + f << N_("still_duration ") << _still_duration << N_("\n"); if (_subtitle_stream) { - f << "selected_subtitle_stream " << _subtitle_stream->to_string() << "\n"; + f << N_("selected_subtitle_stream ") << _subtitle_stream->to_string() << N_("\n"); } - f << "with_subtitles " << _with_subtitles << "\n"; - f << "subtitle_offset " << _subtitle_offset << "\n"; - f << "subtitle_scale " << _subtitle_scale << "\n"; - f << "colour_lut " << _colour_lut << "\n"; - f << "j2k_bandwidth " << _j2k_bandwidth << "\n"; + f << N_("with_subtitles ") << _with_subtitles << N_("\n"); + f << N_("subtitle_offset ") << _subtitle_offset << N_("\n"); + f << N_("subtitle_scale ") << _subtitle_scale << N_("\n"); + f << N_("colour_lut ") << _colour_lut << N_("\n"); + f << N_("j2k_bandwidth ") << _j2k_bandwidth << N_("\n"); _dci_metadata.write (f); - f << "dci_date " << boost::gregorian::to_iso_string (_dci_date) << "\n"; - f << "width " << _size.width << "\n"; - f << "height " << _size.height << "\n"; - f << "length " << _length.get_value_or(0) << "\n"; - f << "dcp_intrinsic_duration " << _dcp_intrinsic_duration.get_value_or(0) << "\n"; - f << "content_digest " << _content_digest << "\n"; + f << N_("dci_date ") << boost::gregorian::to_iso_string (_dci_date) << N_("\n"); + f << N_("width ") << _size.width << N_("\n"); + f << N_("height ") << _size.height << N_("\n"); + f << N_("length ") << _length.get_value_or(0) << N_("\n"); + f << N_("dcp_intrinsic_duration ") << _dcp_intrinsic_duration.get_value_or(0) << N_("\n"); + f << N_("content_digest ") << _content_digest << N_("\n"); for (vector >::const_iterator i = _content_audio_streams.begin(); i != _content_audio_streams.end(); ++i) { - f << "content_audio_stream " << (*i)->to_string () << "\n"; + f << N_("content_audio_stream ") << (*i)->to_string () << N_("\n"); } - f << "external_audio_stream " << _external_audio_stream->to_string() << "\n"; + f << N_("external_audio_stream ") << _external_audio_stream->to_string() << N_("\n"); for (vector >::const_iterator i = _subtitle_streams.begin(); i != _subtitle_streams.end(); ++i) { - f << "subtitle_stream " << (*i)->to_string () << "\n"; + f << N_("subtitle_stream ") << (*i)->to_string () << N_("\n"); } - f << "frames_per_second " << _frames_per_second << "\n"; + f << N_("frames_per_second ") << _frames_per_second << N_("\n"); _dirty = false; } @@ -447,15 +447,15 @@ Film::read_metadata () boost::optional audio_stream_index; boost::optional subtitle_stream_index; - ifstream f (file ("metadata").c_str()); + ifstream f (file (N_("metadata")).c_str()); if (!f.good()) { - throw OpenFileError (file ("metadata")); + throw OpenFileError (file (N_("metadata"))); } multimap kv = read_key_value (f); /* We need version before anything else */ - multimap::iterator v = kv.find ("version"); + multimap::iterator v = kv.find (N_("version")); if (v != kv.end ()) { version = atoi (v->second.c_str()); } @@ -464,107 +464,107 @@ Film::read_metadata () string const k = i->first; string const v = i->second; - if (k == "audio_sample_rate") { + if (k == N_("audio_sample_rate")) { audio_sample_rate = atoi (v.c_str()); } /* User-specified stuff */ - if (k == "name") { + if (k == N_("name")) { _name = v; - } else if (k == "use_dci_name") { - _use_dci_name = (v == "1"); - } else if (k == "content") { + } else if (k == N_("use_dci_name")) { + _use_dci_name = (v == N_("1")); + } else if (k == N_("content")) { _content = v; - } else if (k == "trust_content_header") { - _trust_content_header = (v == "1"); - } else if (k == "dcp_content_type") { + } else if (k == N_("trust_content_header")) { + _trust_content_header = (v == N_("1")); + } else if (k == N_("dcp_content_type")) { if (version < 3) { _dcp_content_type = DCPContentType::from_pretty_name (v); } else { _dcp_content_type = DCPContentType::from_dci_name (v); } - } else if (k == "format") { + } else if (k == N_("format")) { _format = Format::from_metadata (v); - } else if (k == "left_crop") { + } else if (k == N_("left_crop")) { _crop.left = atoi (v.c_str ()); - } else if (k == "right_crop") { + } else if (k == N_("right_crop")) { _crop.right = atoi (v.c_str ()); - } else if (k == "top_crop") { + } else if (k == N_("top_crop")) { _crop.top = atoi (v.c_str ()); - } else if (k == "bottom_crop") { + } else if (k == N_("bottom_crop")) { _crop.bottom = atoi (v.c_str ()); - } else if (k == "filter") { + } else if (k == N_("filter")) { _filters.push_back (Filter::from_id (v)); - } else if (k == "scaler") { + } else if (k == N_("scaler")) { _scaler = Scaler::from_id (v); - } else if ( ((!version || version < 2) && k == "dcp_trim_start") || k == "trim_start") { + } else if ( ((!version || version < 2) && k == N_("dcp_trim_start")) || k == N_("trim_start")) { _trim_start = atoi (v.c_str ()); - } else if ( ((!version || version < 2) && k == "dcp_trim_end") || k == "trim_end") { + } else if ( ((!version || version < 2) && k == N_("dcp_trim_end")) || k == N_("trim_end")) { _trim_end = atoi (v.c_str ()); - } else if (k == "dcp_ab") { - _dcp_ab = (v == "1"); - } else if (k == "selected_content_audio_stream" || (!version && k == "selected_audio_stream")) { + } else if (k == N_("dcp_ab")) { + _dcp_ab = (v == N_("1")); + } else if (k == N_("selected_content_audio_stream") || (!version && k == N_("selected_audio_stream"))) { if (!version) { audio_stream_index = atoi (v.c_str ()); } else { _content_audio_stream = audio_stream_factory (v, version); } - } else if (k == "external_audio") { + } else if (k == N_("external_audio")) { _external_audio.push_back (v); - } else if (k == "use_content_audio") { - _use_content_audio = (v == "1"); - } else if (k == "audio_gain") { + } else if (k == N_("use_content_audio")) { + _use_content_audio = (v == N_("1")); + } else if (k == N_("audio_gain")) { _audio_gain = atof (v.c_str ()); - } else if (k == "audio_delay") { + } else if (k == N_("audio_delay")) { _audio_delay = atoi (v.c_str ()); - } else if (k == "still_duration") { + } else if (k == N_("still_duration")) { _still_duration = atoi (v.c_str ()); - } else if (k == "selected_subtitle_stream") { + } else if (k == N_("selected_subtitle_stream")) { if (!version) { subtitle_stream_index = atoi (v.c_str ()); } else { _subtitle_stream = subtitle_stream_factory (v, version); } - } else if (k == "with_subtitles") { - _with_subtitles = (v == "1"); - } else if (k == "subtitle_offset") { + } else if (k == N_("with_subtitles")) { + _with_subtitles = (v == N_("1")); + } else if (k == N_("subtitle_offset")) { _subtitle_offset = atoi (v.c_str ()); - } else if (k == "subtitle_scale") { + } else if (k == N_("subtitle_scale")) { _subtitle_scale = atof (v.c_str ()); - } else if (k == "colour_lut") { + } else if (k == N_("colour_lut")) { _colour_lut = atoi (v.c_str ()); - } else if (k == "j2k_bandwidth") { + } else if (k == N_("j2k_bandwidth")) { _j2k_bandwidth = atoi (v.c_str ()); - } else if (k == "dci_date") { + } else if (k == N_("dci_date")) { _dci_date = boost::gregorian::from_undelimited_string (v); } _dci_metadata.read (k, v); /* Cached stuff */ - if (k == "width") { + if (k == N_("width")) { _size.width = atoi (v.c_str ()); - } else if (k == "height") { + } else if (k == N_("height")) { _size.height = atoi (v.c_str ()); - } else if (k == "length") { + } else if (k == N_("length")) { int const vv = atoi (v.c_str ()); if (vv) { _length = vv; } - } else if (k == "dcp_intrinsic_duration") { + } else if (k == N_("dcp_intrinsic_duration")) { int const vv = atoi (v.c_str ()); if (vv) { _dcp_intrinsic_duration = vv; } - } else if (k == "content_digest") { + } else if (k == N_("content_digest")) { _content_digest = v; - } else if (k == "content_audio_stream" || (!version && k == "audio_stream")) { + } else if (k == N_("content_audio_stream") || (!version && k == N_("audio_stream"))) { _content_audio_streams.push_back (audio_stream_factory (v, version)); - } else if (k == "external_audio_stream") { + } else if (k == N_("external_audio_stream")) { _external_audio_stream = audio_stream_factory (v, version); - } else if (k == "subtitle_stream") { + } else if (k == N_("subtitle_stream")) { _subtitle_streams.push_back (subtitle_stream_factory (v, version)); - } else if (k == "frames_per_second") { + } else if (k == N_("frames_per_second")) { _frames_per_second = atof (v.c_str ()); } } @@ -714,14 +714,14 @@ Film::dci_name (bool if_created_now) const fixed_name = fixed_name.substr (0, 14); } - d << fixed_name << "_"; + d << fixed_name << N_("_"); if (dcp_content_type()) { - d << dcp_content_type()->dci_name() << "_"; + d << dcp_content_type()->dci_name() << N_("_"); } if (format()) { - d << format()->dci_name() << "_"; + d << format()->dci_name() << N_("_"); } DCIMetadata const dm = dci_metadata (); @@ -729,51 +729,51 @@ Film::dci_name (bool if_created_now) const if (!dm.audio_language.empty ()) { d << dm.audio_language; if (!dm.subtitle_language.empty() && with_subtitles()) { - d << "-" << dm.subtitle_language; + d << N_("-") << dm.subtitle_language; } else { - d << "-XX"; + d << N_("-XX"); } - d << "_"; + d << N_("_"); } if (!dm.territory.empty ()) { d << dm.territory; if (!dm.rating.empty ()) { - d << "-" << dm.rating; + d << N_("-") << dm.rating; } - d << "_"; + d << N_("_"); } switch (audio_channels()) { case 1: - d << "10_"; + d << N_("10_"); break; case 2: - d << "20_"; + d << N_("20_"); break; case 6: - d << "51_"; + d << N_("51_"); break; case 8: - d << "71_"; + d << N_("71_"); break; } - d << "2K_"; + d << N_("2K_"); if (!dm.studio.empty ()) { - d << dm.studio << "_"; + d << dm.studio << N_("_"); } if (if_created_now) { - d << boost::gregorian::to_iso_string (boost::gregorian::day_clock::local_day ()) << "_"; + d << boost::gregorian::to_iso_string (boost::gregorian::day_clock::local_day ()) << N_("_"); } else { - d << boost::gregorian::to_iso_string (_dci_date) << "_"; + d << boost::gregorian::to_iso_string (_dci_date) << N_("_"); } if (!dm.facility.empty ()) { - d << dm.facility << "_"; + d << dm.facility << N_("_"); } if (!dm.package_type.empty ()) { @@ -828,7 +828,7 @@ Film::set_content (string c) { string check = directory (); - boost::filesystem::path slash ("/"); + boost::filesystem::path slash (N_("/")); string platform_slash = slash.make_preferred().string (); if (!ends_with (check, platform_slash)) { @@ -901,10 +901,10 @@ Film::set_content (string c) /* Default format */ switch (content_type()) { case STILL: - set_format (Format::from_id ("var-185")); + set_format (Format::from_id (N_("var-185"))); break; case VIDEO: - set_format (Format::from_id ("185")); + set_format (Format::from_id (N_("185"))); break; } @@ -1332,7 +1332,7 @@ Film::info_path (int f) const stringstream s; s.width (8); - s << setfill('0') << f << ".md5"; + s << setfill('0') << f << N_(".md5"); p /= s.str(); @@ -1346,15 +1346,15 @@ string Film::j2c_path (int f, bool t) const { boost::filesystem::path p; - p /= "j2c"; + p /= N_("j2c"); p /= video_state_identifier (); stringstream s; s.width (8); - s << setfill('0') << f << ".j2c"; + s << setfill('0') << f << N_(".j2c"); if (t) { - s << ".tmp"; + s << N_(".tmp"); } p /= s.str(); diff --git a/src/lib/filter.cc b/src/lib/filter.cc index 9a662f90f..4d429b303 100644 --- a/src/lib/filter.cc +++ b/src/lib/filter.cc @@ -27,6 +27,8 @@ extern "C" { #include } +#include "i18n.h" + using namespace std; vector Filter::_filters; @@ -63,30 +65,30 @@ Filter::setup_filters () { /* Note: "none" is a magic id name, so don't use it here */ - maybe_add ("pphb", "Horizontal deblocking filter", "De-blocking", "", "hb"); - maybe_add ("ppvb", "Vertical deblocking filter", "De-blocking", "", "vb"); - maybe_add ("ppha", "Horizontal deblocking filter A", "De-blocking", "", "ha"); - maybe_add ("ppva", "Vertical deblocking filter A", "De-blocking", "", "va"); - maybe_add ("pph1", "Experimental horizontal deblocking filter 1", "De-blocking", "", "h1"); - maybe_add ("pphv", "Experimental vertical deblocking filter 1", "De-blocking", "", "v1"); - maybe_add ("ppdr", "Deringing filter", "Misc", "", "dr"); - maybe_add ("pplb", "Linear blend deinterlacer", "De-interlacing", "", "lb"); - maybe_add ("ppli", "Linear interpolating deinterlacer", "De-interlacing", "", "li"); - maybe_add ("ppci", "Cubic interpolating deinterlacer", "De-interlacing", "", "ci"); - maybe_add ("ppmd", "Median deinterlacer", "De-interlacing", "", "md"); - maybe_add ("ppfd", "FFMPEG deinterlacer", "De-interlacing", "", "fd"); - maybe_add ("ppl5", "FIR low-pass deinterlacer", "De-interlacing", "", "l5"); - maybe_add ("mcdeint", "Motion compensating deinterlacer", "De-interlacing", "mcdeint", ""); - maybe_add ("kerndeint", "Kernel deinterlacer", "De-interlacing", "kerndeint", ""); - maybe_add ("yadif", "Yet Another Deinterlacing Filter", "De-interlacing", "yadif", ""); - maybe_add ("pptn", "Temporal noise reducer", "Noise reduction", "", "tn"); - maybe_add ("ppfq", "Force quantizer", "Misc", "", "fq"); - maybe_add ("gradfun", "Gradient debander", "Misc", "gradfun", ""); - maybe_add ("unsharp", "Unsharp mask and Gaussian blur", "Misc", "unsharp", ""); - maybe_add ("denoise3d", "3D denoiser", "Noise reduction", "denoise3d", ""); - maybe_add ("hqdn3d", "High quality 3D denoiser", "Noise reduction", "hqdn3d", ""); - maybe_add ("telecine", "Telecine filter", "Misc", "telecine", ""); - maybe_add ("ow", "Overcomplete wavelet denoiser", "Noise reduction", "mp=ow", ""); + maybe_add (N_("pphb"), _("Horizontal deblocking filter"), _("De-blocking"), N_(""), N_("hb")); + maybe_add (N_("ppvb"), _("Vertical deblocking filter"), _("De-blocking"), N_(""), N_("vb")); + maybe_add (N_("ppha"), _("Horizontal deblocking filter A"), _("De-blocking"), N_(""), N_("ha")); + maybe_add (N_("ppva"), _("Vertical deblocking filter A"), _("De-blocking"), N_(""), N_("va")); + maybe_add (N_("pph1"), _("Experimental horizontal deblocking filter 1"), _("De-blocking"), N_(""), N_("h1")); + maybe_add (N_("pphv"), _("Experimental vertical deblocking filter 1"), _("De-blocking"), N_(""), N_("v1")); + maybe_add (N_("ppdr"), _("Deringing filter"), _("Misc"), N_(""), N_("dr")); + maybe_add (N_("pplb"), _("Linear blend deinterlacer"), _("De-interlacing"), N_(""), N_("lb")); + maybe_add (N_("ppli"), _("Linear interpolating deinterlacer"), _("De-interlacing"), N_(""), N_("li")); + maybe_add (N_("ppci"), _("Cubic interpolating deinterlacer"), _("De-interlacing"), N_(""), N_("ci")); + maybe_add (N_("ppmd"), _("Median deinterlacer"), _("De-interlacing"), N_(""), N_("md")); + maybe_add (N_("ppfd"), _("FFMPEG deinterlacer"), _("De-interlacing"), N_(""), N_("fd")); + maybe_add (N_("ppl5"), _("FIR low-pass deinterlacer"), _("De-interlacing"), N_(""), N_("l5")); + maybe_add (N_("mcdeint"), _("Motion compensating deinterlacer"), _("De-interlacing"), N_("mcdeint"), N_("")); + maybe_add (N_("kerndeint"), _("Kernel deinterlacer"), _("De-interlacing"), N_("kerndeint"), N_("")); + maybe_add (N_("yadif"), _("Yet Another Deinterlacing Filter"), _("De-interlacing"), N_("yadif"), N_("")); + maybe_add (N_("pptn"), _("Temporal noise reducer"), _("Noise reduction"), N_(""), N_("tn")); + maybe_add (N_("ppfq"), _("Force quantizer"), _("Misc"), N_(""), N_("fq")); + maybe_add (N_("gradfun"), _("Gradient debander"), _("Misc"), N_("gradfun"), N_("")); + maybe_add (N_("unsharp"), _("Unsharp mask and Gaussian blur"), _("Misc"), N_("unsharp"), N_("")); + maybe_add (N_("denoise3d"), _("3D denoiser"), _("Noise reduction"), N_("denoise3d"), N_("")); + maybe_add (N_("hqdn3d"), _("High quality 3D denoiser"), _("Noise reduction"), N_("hqdn3d"), N_("")); + maybe_add (N_("telecine"), _("Telecine filter"), _("Misc"), N_("telecine"), N_("")); + maybe_add (N_("ow"), _("Overcomplete wavelet denoiser"), _("Noise reduction"), N_("mp=ow"), N_("")); } void @@ -118,14 +120,14 @@ Filter::ffmpeg_strings (vector const & filters) for (vector::const_iterator i = filters.begin(); i != filters.end(); ++i) { if (!(*i)->vf().empty ()) { if (!vf.empty ()) { - vf += ","; + vf += N_(","); } vf += (*i)->vf (); } if (!(*i)->pp().empty ()) { if (!pp.empty()) { - pp += ","; + pp += N_(","); } pp += (*i)->pp (); } diff --git a/src/lib/filter_graph.cc b/src/lib/filter_graph.cc index b0991a2da..045cbaa6a 100644 --- a/src/lib/filter_graph.cc +++ b/src/lib/filter_graph.cc @@ -43,6 +43,8 @@ extern "C" { #include "film.h" #include "ffmpeg_decoder.h" +#include "i18n.h" + using std::stringstream; using std::string; using std::list; @@ -63,36 +65,36 @@ FilterGraph::FilterGraph (shared_ptr film, FFmpegDecoder* decoder, libdcp: { string filters = Filter::ffmpeg_strings (film->filters()).first; if (!filters.empty ()) { - filters += ","; + filters += N_(","); } filters += crop_string (Position (film->crop().left, film->crop().top), film->cropped_size (decoder->native_size())); AVFilterGraph* graph = avfilter_graph_alloc(); if (graph == 0) { - throw DecodeError ("Could not create filter graph."); + throw DecodeError (N_("could not create filter graph.")); } - AVFilter* buffer_src = avfilter_get_by_name("buffer"); + AVFilter* buffer_src = avfilter_get_by_name(N_("buffer")); if (buffer_src == 0) { - throw DecodeError ("Could not find buffer src filter"); + throw DecodeError (N_("could not find buffer src filter")); } AVFilter* buffer_sink = get_sink (); stringstream a; - a << _size.width << ":" - << _size.height << ":" - << _pixel_format << ":" - << decoder->time_base_numerator() << ":" - << decoder->time_base_denominator() << ":" - << decoder->sample_aspect_ratio_numerator() << ":" + a << _size.width << N_(":") + << _size.height << N_(":") + << _pixel_format << N_(":") + << decoder->time_base_numerator() << N_(":") + << decoder->time_base_denominator() << N_(":") + << decoder->sample_aspect_ratio_numerator() << N_(":") << decoder->sample_aspect_ratio_denominator(); int r; - if ((r = avfilter_graph_create_filter (&_buffer_src_context, buffer_src, "in", a.str().c_str(), 0, graph)) < 0) { - throw DecodeError ("could not create buffer source"); + if ((r = avfilter_graph_create_filter (&_buffer_src_context, buffer_src, N_("in"), a.str().c_str(), 0, graph)) < 0) { + throw DecodeError (N_("could not create buffer source")); } AVBufferSinkParams* sink_params = av_buffersink_params_alloc (); @@ -101,34 +103,34 @@ FilterGraph::FilterGraph (shared_ptr film, FFmpegDecoder* decoder, libdcp: pixel_fmts[1] = PIX_FMT_NONE; sink_params->pixel_fmts = pixel_fmts; - if (avfilter_graph_create_filter (&_buffer_sink_context, buffer_sink, "out", 0, sink_params, graph) < 0) { - throw DecodeError ("could not create buffer sink."); + if (avfilter_graph_create_filter (&_buffer_sink_context, buffer_sink, N_("out"), 0, sink_params, graph) < 0) { + throw DecodeError (N_("could not create buffer sink.")); } AVFilterInOut* outputs = avfilter_inout_alloc (); - outputs->name = av_strdup("in"); + outputs->name = av_strdup(N_("in")); outputs->filter_ctx = _buffer_src_context; outputs->pad_idx = 0; outputs->next = 0; AVFilterInOut* inputs = avfilter_inout_alloc (); - inputs->name = av_strdup("out"); + inputs->name = av_strdup(N_("out")); inputs->filter_ctx = _buffer_sink_context; inputs->pad_idx = 0; inputs->next = 0; #if LIBAVFILTER_VERSION_MAJOR == 2 && LIBAVFILTER_VERSION_MINOR == 15 if (avfilter_graph_parse (graph, filters.c_str(), inputs, outputs, 0) < 0) { - throw DecodeError ("could not set up filter graph."); + throw DecodeError (N_("could not set up filter graph.")); } #else if (avfilter_graph_parse (graph, filters.c_str(), &inputs, &outputs, 0) < 0) { - throw DecodeError ("could not set up filter graph."); + throw DecodeError (N_("could not set up filter graph.")); } #endif if (avfilter_graph_config (graph, 0) < 0) { - throw DecodeError ("could not configure filter graph."); + throw DecodeError (N_("could not configure filter graph.")); } /* XXX: leaking `inputs' / `outputs' ? */ @@ -145,7 +147,7 @@ FilterGraph::process (AVFrame const * frame) #if LIBAVFILTER_VERSION_MAJOR == 2 && LIBAVFILTER_VERSION_MINOR >= 53 && LIBAVFILTER_VERSION_MINOR <= 61 if (av_vsrc_buffer_add_frame (_buffer_src_context, frame, 0) < 0) { - throw DecodeError ("could not push buffer into filter chain."); + throw DecodeError (N_("could not push buffer into filter chain.")); } #elif LIBAVFILTER_VERSION_MAJOR == 2 && LIBAVFILTER_VERSION_MINOR == 15 @@ -155,13 +157,13 @@ FilterGraph::process (AVFrame const * frame) par.den = sample_aspect_ratio_denominator (); if (av_vsrc_buffer_add_frame (_buffer_src_context, frame, 0, par) < 0) { - throw DecodeError ("could not push buffer into filter chain."); + throw DecodeError (N_("could not push buffer into filter chain.")); } #else if (av_buffersrc_write_frame (_buffer_src_context, frame) < 0) { - throw DecodeError ("could not push buffer into filter chain."); + throw DecodeError (N_("could not push buffer into filter chain.")); } #endif @@ -176,7 +178,7 @@ FilterGraph::process (AVFrame const * frame) int r = avfilter_request_frame (_buffer_sink_context->inputs[0]); if (r < 0) { - throw DecodeError ("could not request filtered frame"); + throw DecodeError (N_("could not request filtered frame")); } AVFilterBufferRef* filter_buffer = _buffer_sink_context->inputs[0]->cur_buf; diff --git a/src/lib/format.cc b/src/lib/format.cc index 016c21fde..0e4830cd7 100644 --- a/src/lib/format.cc +++ b/src/lib/format.cc @@ -30,6 +30,8 @@ #include "format.h" #include "film.h" +#include "i18n.h" + using std::string; using std::setprecision; using std::stringstream; @@ -45,13 +47,13 @@ FixedFormat::name () const { stringstream s; if (!_nickname.empty ()) { - s << _nickname << " ("; + s << _nickname << N_(" ("); } - s << setprecision(3) << (_ratio / 100.0) << ":1"; + s << setprecision(3) << (_ratio / 100.0) << N_(":1"); if (!_nickname.empty ()) { - s << ")"; + s << N_(")"); } return s.str (); @@ -68,19 +70,20 @@ Format::as_metadata () const void Format::setup_formats () { - _formats.push_back (new FixedFormat (119, libdcp::Size (1285, 1080), "119", "1.19", "F")); - _formats.push_back (new FixedFormat (133, libdcp::Size (1436, 1080), "133", "1.33", "F")); - _formats.push_back (new FixedFormat (138, libdcp::Size (1485, 1080), "138", "1.375", "F")); - _formats.push_back (new FixedFormat (133, libdcp::Size (1998, 1080), "133-in-flat", "4:3 within Flat", "F")); - _formats.push_back (new FixedFormat (137, libdcp::Size (1480, 1080), "137", "Academy", "F")); - _formats.push_back (new FixedFormat (166, libdcp::Size (1793, 1080), "166", "1.66", "F")); - _formats.push_back (new FixedFormat (166, libdcp::Size (1998, 1080), "166-in-flat", "1.66 within Flat", "F")); - _formats.push_back (new FixedFormat (178, libdcp::Size (1998, 1080), "178-in-flat", "16:9 within Flat", "F")); - _formats.push_back (new FixedFormat (178, libdcp::Size (1920, 1080), "178", "16:9", "F")); - _formats.push_back (new FixedFormat (185, libdcp::Size (1998, 1080), "185", "Flat", "F")); - _formats.push_back (new FixedFormat (239, libdcp::Size (2048, 858), "239", "Scope", "S")); - _formats.push_back (new VariableFormat (libdcp::Size (1998, 1080), "var-185", "Flat", "F")); - _formats.push_back (new VariableFormat (libdcp::Size (2048, 858), "var-239", "Scope", "S")); + /// TRANSLATORS: these are film picture aspect ratios; "Academy" means 1.37, "Flat" 1.85 and "Scope" 2.39. + _formats.push_back (new FixedFormat (119, libdcp::Size (1285, 1080), N_("119"), _("1.19"), N_("F"))); + _formats.push_back (new FixedFormat (133, libdcp::Size (1436, 1080), N_("133"), _("1.33"), N_("F"))); + _formats.push_back (new FixedFormat (138, libdcp::Size (1485, 1080), N_("138"), _("1.375"), N_("F"))); + _formats.push_back (new FixedFormat (133, libdcp::Size (1998, 1080), N_("133-in-flat"), _("4:3 within Flat"), N_("F"))); + _formats.push_back (new FixedFormat (137, libdcp::Size (1480, 1080), N_("137"), _("Academy"), N_("F"))); + _formats.push_back (new FixedFormat (166, libdcp::Size (1793, 1080), N_("166"), _("1.66"), N_("F"))); + _formats.push_back (new FixedFormat (166, libdcp::Size (1998, 1080), N_("166-in-flat"), _("1.66 within Flat"), N_("F"))); + _formats.push_back (new FixedFormat (178, libdcp::Size (1998, 1080), N_("178-in-flat"), _("16:9 within Flat"), N_("F"))); + _formats.push_back (new FixedFormat (178, libdcp::Size (1920, 1080), N_("178"), _("16:9"), N_("F"))); + _formats.push_back (new FixedFormat (185, libdcp::Size (1998, 1080), N_("185"), _("Flat"), N_("F"))); + _formats.push_back (new FixedFormat (239, libdcp::Size (2048, 858), N_("239"), _("Scope"), N_("S"))); + _formats.push_back (new VariableFormat (libdcp::Size (1998, 1080), N_("var-185"), _("Flat"), N_("F"))); + _formats.push_back (new VariableFormat (libdcp::Size (2048, 858), N_("var-239"), _("Scope"), N_("S"))); } /** @param n Nickname. diff --git a/src/lib/image.cc b/src/lib/image.cc index b7ac13ab1..268c08173 100644 --- a/src/lib/image.cc +++ b/src/lib/image.cc @@ -40,6 +40,8 @@ extern "C" { #include "exceptions.h" #include "scaler.h" +#include "i18n.h" + using namespace std; using namespace boost; using libdcp::Size; @@ -75,7 +77,7 @@ Image::lines (int n) const case PIX_FMT_YUV444P10LE: return size().height; default: - throw PixelFormatError ("lines()", _pixel_format); + throw PixelFormatError (N_("lines()"), _pixel_format); } return 0; @@ -99,7 +101,7 @@ Image::components () const case PIX_FMT_RGBA: return 1; default: - throw PixelFormatError ("components()", _pixel_format); + throw PixelFormatError (N_("components()"), _pixel_format); } return 0; @@ -218,7 +220,7 @@ Image::post_process (string pp, bool aligned) const case PIX_FMT_YUV444P10LE: pp_format = PP_FORMAT_444; default: - throw PixelFormatError ("post_process", pixel_format()); + throw PixelFormatError (N_("post_process"), pixel_format()); } pp_mode* mode = pp_get_mode_by_name_and_quality (pp.c_str (), PP_QUALITY_MAX); diff --git a/src/lib/imagemagick_decoder.cc b/src/lib/imagemagick_decoder.cc index 42fe699d7..5dc0b7b06 100644 --- a/src/lib/imagemagick_decoder.cc +++ b/src/lib/imagemagick_decoder.cc @@ -25,6 +25,8 @@ #include "film.h" #include "exceptions.h" +#include "i18n.h" + using std::cout; using boost::shared_ptr; using libdcp::Size; @@ -55,7 +57,7 @@ libdcp::Size ImageMagickDecoder::native_size () const { if (_files.empty ()) { - throw DecodeError ("no still image files found"); + throw DecodeError (_("no still image files found")); } /* Look at the first file and assume its size holds for all */ diff --git a/src/lib/job.cc b/src/lib/job.cc index bfad65a0a..77d367136 100644 --- a/src/lib/job.cc +++ b/src/lib/job.cc @@ -27,6 +27,8 @@ #include "job.h" #include "util.h" +#include "i18n.h" + using std::string; using std::list; using std::stringstream; @@ -66,11 +68,12 @@ Job::run_wrapper () set_progress (1); set_state (FINISHED_ERROR); - string m = String::compose ("An error occurred whilst handling the file %1.", boost::filesystem::path (e.filename()).leaf()); + string m = String::compose (_("An error occurred whilst handling the file %1."), boost::filesystem::path (e.filename()).leaf()); boost::filesystem::space_info const s = boost::filesystem::space (e.filename()); if (s.available < pow (1024, 3)) { - m += "\n\nThe drive that the film is stored on is low in disc space. Free some more space and try again."; + m += N_("\n\n"); + m += _("The drive that the film is stored on is low in disc space. Free some more space and try again."); } set_error (e.what(), m); @@ -81,7 +84,7 @@ Job::run_wrapper () set_state (FINISHED_ERROR); set_error ( e.what (), - "It is not known what caused this error. The best idea is to report the problem to the DVD-o-matic mailing list (dvdomatic@carlh.net)" + _("It is not known what caused this error. The best idea is to report the problem to the DVD-o-matic mailing list (dvdomatic@carlh.net)") ); } catch (...) { @@ -89,8 +92,8 @@ Job::run_wrapper () set_progress (1); set_state (FINISHED_ERROR); set_error ( - "Unknown error", - "It is not known what caused this error. The best idea is to report the problem to the DVD-o-matic mailing list (dvdomatic@carlh.net)" + _("Unknown error"), + _("It is not known what caused this error. The best idea is to report the problem to the DVD-o-matic mailing list (dvdomatic@carlh.net)") ); } @@ -273,14 +276,16 @@ Job::status () const stringstream s; if (!finished ()) { - s << pc << "%"; + s << pc << N_("%"); if (p >= 0 && t > 10 && r > 0) { - s << "; " << seconds_to_approximate_hms (r) << " remaining"; + /// TRANSLATORS: remaining here follows an amount of time that is remaining + /// on an operation. + s << "; " << seconds_to_approximate_hms (r) << " " << _("remaining"); } } else if (finished_ok ()) { - s << "OK (ran for " << seconds_to_hms (_ran_for) << ")"; + s << String::compose (_("OK (ran for %1)"), seconds_to_hms (_ran_for)); } else if (finished_in_error ()) { - s << "Error (" << error_summary() << ")"; + s << String::compose (_("Error (%1)"), error_summary()); } return s.str (); diff --git a/src/lib/log.cc b/src/lib/log.cc index 7459700ea..ef36a902c 100644 --- a/src/lib/log.cc +++ b/src/lib/log.cc @@ -25,6 +25,8 @@ #include #include "log.h" +#include "i18n.h" + using namespace std; Log::Log () @@ -48,7 +50,7 @@ Log::log (string m, Level l) string a = ctime (&t); stringstream s; - s << a.substr (0, a.length() - 1) << ": " << m; + s << a.substr (0, a.length() - 1) << N_(": ") << m; do_log (s.str ()); } @@ -65,7 +67,7 @@ Log::microsecond_log (string m, Level l) gettimeofday (&tv, 0); stringstream s; - s << tv.tv_sec << ":" << tv.tv_usec << " " << m; + s << tv.tv_sec << N_(":") << tv.tv_usec << N_(" ") << m; do_log (s.str ()); } @@ -79,10 +81,10 @@ Log::set_level (Level l) void Log::set_level (string l) { - if (l == "verbose") { + if (l == N_("verbose")) { set_level (VERBOSE); return; - } else if (l == "timing") { + } else if (l == N_("timing")) { set_level (TIMING); return; } @@ -101,6 +103,6 @@ void FileLog::do_log (string m) { ofstream f (_file.c_str(), fstream::app); - f << m << "\n"; + f << m << N_("\n"); } diff --git a/src/lib/matcher.cc b/src/lib/matcher.cc index 182fb306c..4cd264338 100644 --- a/src/lib/matcher.cc +++ b/src/lib/matcher.cc @@ -21,6 +21,8 @@ #include "image.h" #include "log.h" +#include "i18n.h" + using std::min; using boost::shared_ptr; @@ -65,7 +67,7 @@ Matcher::process_end () _log->log ( String::compose ( - "Matching processor has seen %1 video frames (which equals %2 audio frames) and %3 audio frames", + N_("Matching processor has seen %1 video frames (which equals %2 audio frames) and %3 audio frames"), _video_frames, video_frames_to_audio_frames (_video_frames, _sample_rate, _frames_per_second), _audio_frames @@ -74,12 +76,12 @@ Matcher::process_end () if (audio_short_by_frames < 0) { - _log->log (String::compose ("%1 too many audio frames", -audio_short_by_frames)); + _log->log (String::compose (N_("%1 too many audio frames"), -audio_short_by_frames)); /* We have seen more audio than video. Emit enough black video frames so that we reverse this */ int const black_video_frames = ceil (-audio_short_by_frames * _frames_per_second / _sample_rate); - _log->log (String::compose ("Emitting %1 frames of black video", black_video_frames)); + _log->log (String::compose (N_("Emitting %1 frames of black video"), black_video_frames)); shared_ptr black (new SimpleImage (_pixel_format.get(), _size.get(), true)); black->make_black (); @@ -92,7 +94,7 @@ Matcher::process_end () } if (audio_short_by_frames > 0) { - _log->log (String::compose ("Emitted %1 too few audio frames", audio_short_by_frames)); + _log->log (String::compose (N_("Emitted %1 too few audio frames"), audio_short_by_frames)); /* Do things in half second blocks as I think there may be limits to what FFmpeg (and in particular the resampler) can cope with. diff --git a/src/lib/scaler.cc b/src/lib/scaler.cc index c81456a15..40a0f05b9 100644 --- a/src/lib/scaler.cc +++ b/src/lib/scaler.cc @@ -28,6 +28,8 @@ extern "C" { } #include "scaler.h" +#include "i18n.h" + using namespace std; vector Scaler::_scalers; @@ -57,15 +59,15 @@ Scaler::all () void Scaler::setup_scalers () { - _scalers.push_back (new Scaler (SWS_BICUBIC, "bicubic", "Bicubic")); - _scalers.push_back (new Scaler (SWS_X, "x", "X")); - _scalers.push_back (new Scaler (SWS_AREA, "area", "Area")); - _scalers.push_back (new Scaler (SWS_GAUSS, "gauss", "Gaussian")); - _scalers.push_back (new Scaler (SWS_LANCZOS, "lanczos", "Lanczos")); - _scalers.push_back (new Scaler (SWS_SINC, "sinc", "Sinc")); - _scalers.push_back (new Scaler (SWS_SPLINE, "spline", "Spline")); - _scalers.push_back (new Scaler (SWS_BILINEAR, "bilinear", "Bilinear")); - _scalers.push_back (new Scaler (SWS_FAST_BILINEAR, "fastbilinear", "Fast Bilinear")); + _scalers.push_back (new Scaler (SWS_BICUBIC, N_("bicubic"), _("Bicubic"))); + _scalers.push_back (new Scaler (SWS_X, N_("x"), _("X"))); + _scalers.push_back (new Scaler (SWS_AREA, N_("area"), _("Area"))); + _scalers.push_back (new Scaler (SWS_GAUSS, N_("gauss"), _("Gaussian"))); + _scalers.push_back (new Scaler (SWS_LANCZOS, N_("lanczos"), _("Lanczos"))); + _scalers.push_back (new Scaler (SWS_SINC, N_("sinc"), _("Sinc"))); + _scalers.push_back (new Scaler (SWS_SPLINE, N_("spline"), _("Spline"))); + _scalers.push_back (new Scaler (SWS_BILINEAR, N_("bilinear"), _("Bilinear"))); + _scalers.push_back (new Scaler (SWS_FAST_BILINEAR, N_("fastbilinear"), _("Fast Bilinear"))); } /** @param id One of our ids. diff --git a/src/lib/scp_dcp_job.cc b/src/lib/scp_dcp_job.cc index 30d02eff8..a9fdfefda 100644 --- a/src/lib/scp_dcp_job.cc +++ b/src/lib/scp_dcp_job.cc @@ -34,6 +34,8 @@ #include "log.h" #include "film.h" +#include "i18n.h" + using std::string; using std::stringstream; using std::min; @@ -47,7 +49,7 @@ public: { session = ssh_new (); if (session == 0) { - throw NetworkError ("Could not start SSH session"); + throw NetworkError (_("could not start SSH session")); } } @@ -81,7 +83,7 @@ public: { scp = ssh_scp_new (s, SSH_SCP_WRITE | SSH_SCP_RECURSIVE, Config::instance()->tms_path().c_str ()); if (!scp) { - throw NetworkError (String::compose ("Could not start SCP session (%1)", ssh_get_error (s))); + throw NetworkError (String::compose (_("could not start SCP session (%1)"), ssh_get_error (s))); } } @@ -96,7 +98,7 @@ public: SCPDCPJob::SCPDCPJob (shared_ptr f) : Job (f) - , _status ("Waiting") + , _status (_("Waiting")) { } @@ -104,17 +106,17 @@ SCPDCPJob::SCPDCPJob (shared_ptr f) string SCPDCPJob::name () const { - return "Copy DCP to TMS"; + return _("Copy DCP to TMS"); } void SCPDCPJob::run () { - _film->log()->log ("SCP DCP job starting"); + _film->log()->log (N_("SCP DCP job starting")); SSHSession ss; - set_status ("connecting"); + set_status (_("connecting")); ssh_options_set (ss.session, SSH_OPTIONS_HOST, Config::instance()->tms_ip().c_str ()); ssh_options_set (ss.session, SSH_OPTIONS_USER, Config::instance()->tms_user().c_str ()); @@ -123,29 +125,29 @@ SCPDCPJob::run () int r = ss.connect (); if (r != SSH_OK) { - throw NetworkError (String::compose ("Could not connect to server %1 (%2)", Config::instance()->tms_ip(), ssh_get_error (ss.session))); + throw NetworkError (String::compose (_("Could not connect to server %1 (%2)"), Config::instance()->tms_ip(), ssh_get_error (ss.session))); } int const state = ssh_is_server_known (ss.session); if (state == SSH_SERVER_ERROR) { - throw NetworkError (String::compose ("SSH error (%1)", ssh_get_error (ss.session))); + throw NetworkError (String::compose (_("SSH error (%1)"), ssh_get_error (ss.session))); } r = ssh_userauth_password (ss.session, 0, Config::instance()->tms_password().c_str ()); if (r != SSH_AUTH_SUCCESS) { - throw NetworkError (String::compose ("Failed to authenticate with server (%1)", ssh_get_error (ss.session))); + throw NetworkError (String::compose (_("Failed to authenticate with server (%1)"), ssh_get_error (ss.session))); } SSHSCP sc (ss.session); r = ssh_scp_init (sc.scp); if (r != SSH_OK) { - throw NetworkError (String::compose ("Could not start SCP session (%1)", ssh_get_error (ss.session))); + throw NetworkError (String::compose (_("Could not start SCP session (%1)"), ssh_get_error (ss.session))); } r = ssh_scp_push_directory (sc.scp, _film->dcp_name().c_str(), S_IRWXU); if (r != SSH_OK) { - throw NetworkError (String::compose ("Could not create remote directory %1 (%2)", _film->dcp_name(), ssh_get_error (ss.session))); + throw NetworkError (String::compose (_("Could not create remote directory %1 (%2)"), _film->dcp_name(), ssh_get_error (ss.session))); } string const dcp_dir = _film->dir (_film->dcp_name()); @@ -163,14 +165,14 @@ SCPDCPJob::run () string const leaf = boost::filesystem::path(*i).leaf().generic_string (); - set_status ("copying " + leaf); + set_status (String::compose (_("copying %1"), leaf)); boost::uintmax_t to_do = boost::filesystem::file_size (*i); ssh_scp_push_file (sc.scp, leaf.c_str(), to_do, S_IRUSR | S_IWUSR); - FILE* f = fopen (boost::filesystem::path (*i).string().c_str(), "rb"); + FILE* f = fopen (boost::filesystem::path (*i).string().c_str(), N_("rb")); if (f == 0) { - throw NetworkError (String::compose ("Could not open %1 to send", *i)); + throw NetworkError (String::compose (_("Could not open %1 to send"), *i)); } while (to_do > 0) { @@ -182,7 +184,7 @@ SCPDCPJob::run () r = ssh_scp_write (sc.scp, buffer, t); if (r != SSH_OK) { - throw NetworkError (String::compose ("Could not write to remote file (%1)", ssh_get_error (ss.session))); + throw NetworkError (String::compose (_("Could not write to remote file (%1)"), ssh_get_error (ss.session))); } to_do -= t; bytes_transferred += t; @@ -194,7 +196,7 @@ SCPDCPJob::run () } set_progress (1); - set_status (""); + set_status (N_("")); set_state (FINISHED_OK); } @@ -205,7 +207,7 @@ SCPDCPJob::status () const stringstream s; s << Job::status (); if (!_status.empty ()) { - s << "; " << _status; + s << N_("; ") << _status; } return s.str (); } diff --git a/src/lib/server.cc b/src/lib/server.cc index 3614ed9e4..76a25bfbb 100644 --- a/src/lib/server.cc +++ b/src/lib/server.cc @@ -37,6 +37,8 @@ #include "config.h" #include "subtitle.h" +#include "i18n.h" + using std::string; using std::stringstream; using std::multimap; @@ -57,7 +59,7 @@ ServerDescription * ServerDescription::create_from_metadata (string v) { vector b; - split (b, v, is_any_of (" ")); + split (b, v, is_any_of (N_(" "))); if (b.size() != 2) { return 0; @@ -71,7 +73,7 @@ string ServerDescription::as_metadata () const { stringstream s; - s << _host_name << " " << _threads; + s << _host_name << N_(" ") << _threads; return s.str (); } @@ -91,24 +93,24 @@ Server::process (shared_ptr socket) stringstream s (buffer.get()); multimap kv = read_key_value (s); - if (get_required_string (kv, "encode") != "please") { + if (get_required_string (kv, N_("encode")) != N_("please")) { return -1; } - libdcp::Size in_size (get_required_int (kv, "input_width"), get_required_int (kv, "input_height")); - int pixel_format_int = get_required_int (kv, "input_pixel_format"); - libdcp::Size out_size (get_required_int (kv, "output_width"), get_required_int (kv, "output_height")); - int padding = get_required_int (kv, "padding"); - int subtitle_offset = get_required_int (kv, "subtitle_offset"); - float subtitle_scale = get_required_float (kv, "subtitle_scale"); - string scaler_id = get_required_string (kv, "scaler"); - int frame = get_required_int (kv, "frame"); - int frames_per_second = get_required_int (kv, "frames_per_second"); - string post_process = get_optional_string (kv, "post_process"); - int colour_lut_index = get_required_int (kv, "colour_lut"); - int j2k_bandwidth = get_required_int (kv, "j2k_bandwidth"); - Position subtitle_position (get_optional_int (kv, "subtitle_x"), get_optional_int (kv, "subtitle_y")); - libdcp::Size subtitle_size (get_optional_int (kv, "subtitle_width"), get_optional_int (kv, "subtitle_height")); + 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")); + string post_process = get_optional_string (kv, N_("post_process")); + 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"))); /* This checks that colour_lut_index is within range */ colour_lut_index_to_name (colour_lut_index); @@ -137,7 +139,7 @@ Server::process (shared_ptr socket) encoded->send (socket); } catch (std::exception& e) { _log->log (String::compose ( - "Send failed; frame %1, data size %2, pixel format %3, image size %4x%5, %6 components", + N_("Send failed; frame %1, data size %2, pixel format %3, image size %4x%5, %6 components"), frame, encoded->size(), image->pixel_format(), image->size().width, image->size().height, image->components() ) ); @@ -169,7 +171,7 @@ Server::worker_thread () try { frame = process (socket); } catch (std::exception& e) { - _log->log (String::compose ("Error: %1", e.what())); + _log->log (String::compose (N_("Error: %1"), e.what())); } socket.reset (); @@ -179,7 +181,7 @@ Server::worker_thread () if (frame >= 0) { struct timeval end; gettimeofday (&end, 0); - _log->log (String::compose ("Encoded frame %1 in %2", frame, seconds (end) - seconds (start))); + _log->log (String::compose (N_("Encoded frame %1 in %2"), frame, seconds (end) - seconds (start))); } _worker_condition.notify_all (); @@ -189,7 +191,7 @@ Server::worker_thread () void Server::run (int num_threads) { - _log->log (String::compose ("Server starting with %1 threads", num_threads)); + _log->log (String::compose (N_("Server starting with %1 threads"), num_threads)); for (int i = 0; i < num_threads; ++i) { _worker_threads.push_back (new thread (bind (&Server::worker_thread, this))); diff --git a/src/lib/stream.cc b/src/lib/stream.cc index 4f12f41b9..e5a2bbc2b 100644 --- a/src/lib/stream.cc +++ b/src/lib/stream.cc @@ -23,6 +23,8 @@ #include "ffmpeg_decoder.h" #include "external_audio_decoder.h" +#include "i18n.h" + using std::string; using std::stringstream; using boost::shared_ptr; @@ -47,7 +49,7 @@ SubtitleStream::SubtitleStream (string t, boost::optional) string SubtitleStream::to_string () const { - return String::compose ("%1 %2", _id, _name); + return String::compose (N_("%1 %2"), _id, _name); } /** Create a SubtitleStream from a value returned from to_string(). diff --git a/src/lib/subtitle.cc b/src/lib/subtitle.cc index 5bb91af63..5c1ad9706 100644 --- a/src/lib/subtitle.cc +++ b/src/lib/subtitle.cc @@ -25,6 +25,8 @@ #include "image.h" #include "exceptions.h" +#include "i18n.h" + using namespace std; using namespace boost; using libdcp::Size; @@ -47,13 +49,13 @@ TimedSubtitle::TimedSubtitle (AVSubtitle const & sub) _to = packet_time + (double (sub.end_display_time) / 1e3); if (sub.num_rects > 1) { - throw DecodeError ("multi-part subtitles not yet supported"); + throw DecodeError (_("multi-part subtitles not yet supported")); } AVSubtitleRect const * rect = sub.rects[0]; if (rect->type != SUBTITLE_BITMAP) { - throw DecodeError ("non-bitmap subtitles not yet supported"); + throw DecodeError (_("non-bitmap subtitles not yet supported")); } shared_ptr image (new SimpleImage (PIX_FMT_RGBA, libdcp::Size (rect->w, rect->h), true)); diff --git a/src/lib/timer.cc b/src/lib/timer.cc index a45e80dcb..69a7e3aa9 100644 --- a/src/lib/timer.cc +++ b/src/lib/timer.cc @@ -26,6 +26,8 @@ #include "timer.h" #include "util.h" +#include "i18n.h" + using namespace std; /** @param n Name to use when giving output */ @@ -40,7 +42,7 @@ PeriodTimer::~PeriodTimer () { struct timeval stop; gettimeofday (&stop, 0); - cout << "T: " << _name << ": " << (seconds (stop) - seconds (_start)) << "\n"; + cout << N_("T: ") << _name << N_(": ") << (seconds (stop) - seconds (_start)) << N_("\n"); } /** @param n Name to use when giving output. @@ -80,10 +82,10 @@ StateTimer::~StateTimer () } - set_state (""); + set_state (N_("")); - cout << _name << ":\n"; + cout << _name << N_(":\n"); for (map::iterator i = _totals.begin(); i != _totals.end(); ++i) { - cout << "\t" << i->first << " " << i->second << "\n"; + cout << N_("\t") << i->first << " " << i->second << N_("\n"); } } diff --git a/src/lib/transcode_job.cc b/src/lib/transcode_job.cc index a4279ef8b..61fad2e2b 100644 --- a/src/lib/transcode_job.cc +++ b/src/lib/transcode_job.cc @@ -59,8 +59,8 @@ TranscodeJob::run () { try { - _film->log()->log ("Transcode job starting"); - _film->log()->log (String::compose ("Audio delay is %1ms", _film->audio_delay())); + _film->log()->log (N_("Transcode job starting")); + _film->log()->log (String::compose (N_("Audio delay is %1ms"), _film->audio_delay())); _encoder.reset (new Encoder (_film)); Transcoder w (_film, _decode_opt, this, _encoder); @@ -70,14 +70,14 @@ TranscodeJob::run () _film->set_dcp_intrinsic_duration (_encoder->video_frames_out ()); - _film->log()->log ("Transcode job completed successfully"); - _film->log()->log (String::compose ("DCP intrinsic duration is %1", _encoder->video_frames_out())); + _film->log()->log (N_("Transcode job completed successfully")); + _film->log()->log (String::compose (N_("DCP intrinsic duration is %1"), _encoder->video_frames_out())); } catch (std::exception& e) { set_progress (1); set_state (FINISHED_ERROR); - _film->log()->log (String::compose ("Transcode job failed (%1)", e.what())); + _film->log()->log (String::compose (N_("Transcode job failed (%1)"), e.what())); throw; } @@ -87,7 +87,7 @@ string TranscodeJob::status () const { if (!_encoder) { - return "0%"; + return _("0%"); } float const fps = _encoder->current_frames_per_second (); @@ -100,7 +100,7 @@ TranscodeJob::status () const s << Job::status (); if (!finished ()) { - s << "; " << fixed << setprecision (1) << fps << " " << _("frames per second"); + s << N_("; ") << fixed << setprecision (1) << fps << N_(" ") << _("frames per second"); } return s.str (); diff --git a/src/lib/util.cc b/src/lib/util.cc index 4ee304600..892a7fd86 100644 --- a/src/lib/util.cc +++ b/src/lib/util.cc @@ -61,6 +61,8 @@ extern "C" { #include "sound_processor.h" #include "config.h" +#include "i18n.h" + using namespace std; using namespace boost; using libdcp::Size; @@ -83,9 +85,9 @@ seconds_to_hms (int s) m -= (h * 60); stringstream hms; - hms << h << ":"; + hms << h << N_(":"); hms.width (2); - hms << setfill ('0') << m << ":"; + hms << setfill ('0') << m << N_(":"); hms.width (2); hms << setfill ('0') << s; @@ -107,22 +109,22 @@ seconds_to_approximate_hms (int s) if (h > 0) { if (m > 30) { - ap << (h + 1) << " hours"; + ap << (h + 1) << N_(" ") << _("hours"); } else { if (h == 1) { - ap << "1 hour"; + ap << N_("1 ") << _("hour"); } else { - ap << h << " hours"; + ap << h << N_(" ") << _("hours"); } } } else if (m > 0) { if (m == 1) { - ap << "1 minute"; + ap << N_("1 ") << _("minute"); } else { - ap << m << " minutes"; + ap << m << N_(" ") << _("minutes"); } } else { - ap << s << " seconds"; + ap << s << N_(" ") << _("seconds"); } return ap.str (); @@ -135,12 +137,12 @@ seconds_to_approximate_hms (int s) static string demangle (string l) { - string::size_type const b = l.find_first_of ("("); + string::size_type const b = l.find_first_of (N_("(")); if (b == string::npos) { return l; } - string::size_type const p = l.find_last_of ("+"); + string::size_type const p = l.find_last_of (N_("+")); if (p == string::npos) { return l; } @@ -183,7 +185,7 @@ stacktrace (ostream& out, int levels) if (strings) { for (i = 0; i < size && (levels == 0 || i < size_t(levels)); i++) { - out << " " << demangle (strings[i]) << endl; + out << N_(" ") << demangle (strings[i]) << endl; } free (strings); @@ -198,7 +200,7 @@ static string ffmpeg_version_to_string (int v) { stringstream s; - s << ((v & 0xff0000) >> 16) << "." << ((v & 0xff00) >> 8) << "." << (v & 0xff); + s << ((v & 0xff0000) >> 16) << N_(".") << ((v & 0xff00) >> 8) << N_(".") << (v & 0xff); return s.str (); } @@ -207,16 +209,16 @@ string dependency_version_summary () { stringstream s; - s << "libopenjpeg " << opj_version () << ", " - << "libavcodec " << ffmpeg_version_to_string (avcodec_version()) << ", " - << "libavfilter " << ffmpeg_version_to_string (avfilter_version()) << ", " - << "libavformat " << ffmpeg_version_to_string (avformat_version()) << ", " - << "libavutil " << ffmpeg_version_to_string (avutil_version()) << ", " - << "libpostproc " << ffmpeg_version_to_string (postproc_version()) << ", " - << "libswscale " << ffmpeg_version_to_string (swscale_version()) << ", " - << MagickVersion << ", " - << "libssh " << ssh_version (0) << ", " - << "libdcp " << libdcp::version << " git " << libdcp::git_commit; + s << N_("libopenjpeg ") << opj_version () << N_(", ") + << N_("libavcodec ") << ffmpeg_version_to_string (avcodec_version()) << N_(", ") + << N_("libavfilter ") << ffmpeg_version_to_string (avfilter_version()) << N_(", ") + << N_("libavformat ") << ffmpeg_version_to_string (avformat_version()) << N_(", ") + << N_("libavutil ") << ffmpeg_version_to_string (avutil_version()) << N_(", ") + << N_("libpostproc ") << ffmpeg_version_to_string (postproc_version()) << N_(", ") + << N_("libswscale ") << ffmpeg_version_to_string (swscale_version()) << N_(", ") + << MagickVersion << N_(", ") + << N_("libssh ") << ssh_version (0) << N_(", ") + << N_("libdcp ") << libdcp::version << N_(" git ") << libdcp::git_commit; return s.str (); } @@ -233,6 +235,8 @@ seconds (struct timeval t) void dvdomatic_setup () { + bindtextdomain ("libdvdomatic", LOCALE_DIR); + avfilter_register_all (); Format::setup_formats (); @@ -252,7 +256,7 @@ string crop_string (Position start, libdcp::Size size) { stringstream s; - s << "crop=" << size.width << ":" << size.height << ":" << start.x << ":" << start.y; + s << N_("crop=") << size.width << N_(":") << size.height << N_(":") << start.x << N_(":") << start.y; return s.str (); } @@ -268,7 +272,7 @@ split_at_spaces_considering_quotes (string s) for (string::size_type i = 0; i < s.length(); ++i) { if (s[i] == ' ' && !in_quotes) { out.push_back (c); - c = ""; + c = N_(""); } else if (s[i] == '"') { in_quotes = !in_quotes; } else { @@ -423,7 +427,7 @@ DCPFrameRate::DCPFrameRate (float source_fps) } if (!best) { - throw EncodeError ("cannot find a suitable DCP frame rate for this source"); + throw EncodeError (_("cannot find a suitable DCP frame rate for this source")); } frames_per_second = best->dcp; @@ -476,13 +480,13 @@ colour_lut_index_to_name (int index) { switch (index) { case 0: - return "sRGB"; + return _("sRGB"); case 1: - return "Rec 709"; + return _("Rec 709"); } assert (false); - return ""; + return N_(""); } Socket::Socket (int timeout) @@ -519,7 +523,7 @@ Socket::connect (asio::ip::basic_resolver_entry const & endpoint) } while (ec == asio::error::would_block); if (ec || !_socket.is_open ()) { - throw NetworkError ("connect timed out"); + throw NetworkError (_("connect timed out")); } } @@ -656,13 +660,13 @@ string get_required_string (multimap const & kv, string k) { if (kv.count (k) > 1) { - throw StringError ("unexpected multiple keys in key-value set"); + throw StringError (N_("unexpected multiple keys in key-value set")); } multimap::const_iterator i = kv.find (k); if (i == kv.end ()) { - throw StringError (String::compose ("missing key %1 in key-value set", k)); + throw StringError (String::compose (_("missing key %1 in key-value set"), k)); } return i->second; @@ -686,12 +690,12 @@ string get_optional_string (multimap const & kv, string k) { if (kv.count (k) > 1) { - throw StringError ("unexpected multiple keys in key-value set"); + throw StringError (N_("unexpected multiple keys in key-value set")); } multimap::const_iterator i = kv.find (k); if (i == kv.end ()) { - return ""; + return N_(""); } return i->second; @@ -701,7 +705,7 @@ int get_optional_int (multimap const & kv, string k) { if (kv.count (k) > 1) { - throw StringError ("unexpected multiple keys in key-value set"); + throw StringError (N_("unexpected multiple keys in key-value set")); } multimap::const_iterator i = kv.find (k); @@ -870,7 +874,7 @@ still_image_file (string f) transform (ext.begin(), ext.end(), ext.begin(), ::tolower); - return (ext == ".tif" || ext == ".tiff" || ext == ".jpg" || ext == ".jpeg" || ext == ".png" || ext == ".bmp"); + return (ext == N_(".tif") || ext == N_(".tiff") || ext == N_(".jpg") || ext == N_(".jpeg") || ext == N_(".png") || ext == N_(".bmp")); } /** @return A pair containing CPU model name and the number of processors */ @@ -881,16 +885,16 @@ cpu_info () info.second = 0; #ifdef DVDOMATIC_POSIX - ifstream f ("/proc/cpuinfo"); + ifstream f (N_("/proc/cpuinfo")); while (f.good ()) { string l; getline (f, l); - if (boost::algorithm::starts_with (l, "model name")) { + if (boost::algorithm::starts_with (l, N_("model name"))) { string::size_type const c = l.find (':'); if (c != string::npos) { info.first = l.substr (c + 2); } - } else if (boost::algorithm::starts_with (l, "processor")) { + } else if (boost::algorithm::starts_with (l, N_("processor"))) { ++info.second; } } diff --git a/src/lib/video_decoder.cc b/src/lib/video_decoder.cc index c1f48cb5e..891720f6b 100644 --- a/src/lib/video_decoder.cc +++ b/src/lib/video_decoder.cc @@ -25,6 +25,8 @@ #include "options.h" #include "job.h" +#include "i18n.h" + using boost::shared_ptr; using boost::optional; @@ -76,7 +78,7 @@ VideoDecoder::repeat_last_video () void VideoDecoder::signal_video (shared_ptr image, bool same, shared_ptr sub) { - TIMING ("Decoder emits %1", _video_frame); + TIMING (N_("Decoder emits %1"), _video_frame); Video (image, same, sub); ++_video_frame; diff --git a/src/lib/writer.cc b/src/lib/writer.cc index c2cc00328..d480d502a 100644 --- a/src/lib/writer.cc +++ b/src/lib/writer.cc @@ -29,6 +29,8 @@ #include "log.h" #include "dcp_video_frame.h" +#include "i18n.h" + using std::make_pair; using std::pair; using std::string; @@ -76,7 +78,7 @@ Writer::Writer (shared_ptr f) _sound_asset.reset ( new libdcp::SoundAsset ( _film->dir (_film->dcp_name()), - "audio.mxf", + N_("audio.mxf"), DCPFrameRate (_film->frames_per_second()).frames_per_second, dcp_audio_channels (_film->audio_channels()), dcp_audio_sample_rate (_film->audio_stream()->sample_rate()) @@ -147,9 +149,9 @@ try break; } - TIMING ("writer sleeps with a queue of %1", _queue.size()); + TIMING (N_("writer sleeps with a queue of %1"), _queue.size()); _condition.wait (lock); - TIMING ("writer wakes with a queue of %1", _queue.size()); + TIMING (N_("writer wakes with a queue of %1"), _queue.size()); } if (_finish && _queue.empty()) { @@ -168,7 +170,7 @@ try switch (qi.type) { case QueueItem::FULL: { - _film->log()->log (String::compose ("Writer FULL-writes %1 to MXF", qi.frame)); + _film->log()->log (String::compose (N_("Writer FULL-writes %1 to MXF"), qi.frame)); if (!qi.encoded) { qi.encoded.reset (new EncodedData (_film->j2c_path (qi.frame, false))); } @@ -179,14 +181,14 @@ try break; } case QueueItem::FAKE: - _film->log()->log (String::compose ("Writer FAKE-writes %1 to MXF", qi.frame)); + _film->log()->log (String::compose (N_("Writer FAKE-writes %1 to MXF"), qi.frame)); _picture_asset_writer->fake_write (qi.size); _last_written.reset (); ++_fake_written; break; case QueueItem::REPEAT: { - _film->log()->log (String::compose ("Writer REPEAT-writes %1 to MXF", qi.frame)); + _film->log()->log (String::compose (N_("Writer REPEAT-writes %1 to MXF"), qi.frame)); libdcp::FrameInfo const fin = _picture_asset_writer->write (_last_written->data(), _last_written->size()); _last_written->write_info (_film, qi.frame, fin); ++_repeat_written; @@ -215,7 +217,7 @@ try ++_pushed_to_disk; lock.unlock (); - _film->log()->log (String::compose ("Writer full (awaiting %1); pushes %2 to disk", _last_written_frame + 1, qi.frame)); + _film->log()->log (String::compose (N_("Writer full (awaiting %1); pushes %2 to disk"), _last_written_frame + 1, qi.frame)); qi.encoded->write (_film, qi.frame); lock.lock (); qi.encoded.reset (); @@ -270,14 +272,14 @@ Writer::finish () boost::filesystem::path to; to /= _film->dir (_film->dcp_name()); - to /= "video.mxf"; + to /= N_("video.mxf"); boost::filesystem::create_hard_link (from, to); /* And update the asset */ _picture_asset->set_directory (_film->dir (_film->dcp_name ())); - _picture_asset->set_file_name ("video.mxf"); + _picture_asset->set_file_name (N_("video.mxf")); if (_sound_asset) { _sound_asset->set_entry_point (_film->trim_start ()); @@ -302,7 +304,7 @@ Writer::finish () dcp.write_xml (); - _film->log()->log (String::compose ("Wrote %1 FULL, %2 FAKE, %3 REPEAT; %4 pushed to disk", _full_written, _fake_written, _repeat_written, _pushed_to_disk)); + _film->log()->log (String::compose (N_("Wrote %1 FULL, %2 FAKE, %3 REPEAT; %4 pushed to disk"), _full_written, _fake_written, _repeat_written, _pushed_to_disk)); } /** Tell the writer that frame `f' should be a repeat of the frame before it */ @@ -328,7 +330,7 @@ Writer::check_existing_picture_mxf () boost::filesystem::path p; p /= _film->video_mxf_dir (); p /= _film->video_mxf_filename (); - FILE* mxf = fopen (p.string().c_str(), "rb"); + FILE* mxf = fopen (p.string().c_str(), N_("rb")); if (!mxf) { return; } @@ -346,11 +348,11 @@ Writer::check_existing_picture_mxf () string const existing_hash = md5_digest (data.data(), data.size()); if (existing_hash != info.hash) { - _film->log()->log (String::compose ("Existing frame %1 failed hash check", _first_nonexistant_frame)); + _film->log()->log (String::compose (N_("Existing frame %1 failed hash check"), _first_nonexistant_frame)); break; } - _film->log()->log (String::compose ("Have existing frame %1", _first_nonexistant_frame)); + _film->log()->log (String::compose (N_("Have existing frame %1"), _first_nonexistant_frame)); ++_first_nonexistant_frame; } diff --git a/src/tools/dvdomatic.cc b/src/tools/dvdomatic.cc index d1760c327..52e551d2a 100644 --- a/src/tools/dvdomatic.cc +++ b/src/tools/dvdomatic.cc @@ -441,15 +441,9 @@ setup_i18n () if (wxLocale::IsAvailable (language)) { locale = new wxLocale (language, wxLOCALE_LOAD_DEFAULT); - + #ifdef __WXGTK__ - locale->AddCatalogLookupPathPrefix (wxT ("/usr")); - locale->AddCatalogLookupPathPrefix (wxT ("/usr/local")); - locale->AddCatalogLookupPathPrefix (wxT ("build/src/wx/mo")); - locale->AddCatalogLookupPathPrefix (wxT ("build/src/tools/mo")); - wxStandardPaths* paths = (wxStandardPaths*) &wxStandardPaths::Get(); - wxString prefix = paths->GetInstallPrefix(); - locale->AddCatalogLookupPathPrefix (prefix); + locale->AddCatalogLookupPathPrefix (wxT (LOCALE_DIR)); #endif locale->AddCatalog ("libdvdomatic-wx"); diff --git a/src/wx/config_dialog.cc b/src/wx/config_dialog.cc index 07e32a457..bf97d0d3a 100644 --- a/src/wx/config_dialog.cc +++ b/src/wx/config_dialog.cc @@ -154,7 +154,7 @@ ConfigDialog::ConfigDialog (wxWindow* parent) _reference_scaler->Connect (wxID_ANY, wxEVT_COMMAND_CHOICE_SELECTED, wxCommandEventHandler (ConfigDialog::reference_scaler_changed), 0, this); pair p = Filter::ffmpeg_strings (config->reference_filters ()); - _reference_filters->SetLabel (std_to_wx (p.first + " " + p.second)); + _reference_filters->SetLabel (std_to_wx (p.first + N_(" ") + p.second)); _reference_filters_button->Connect (wxID_ANY, wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler (ConfigDialog::edit_reference_filters_clicked), 0, this); vector servers = config->servers (); @@ -313,7 +313,7 @@ ConfigDialog::reference_filters_changed (vector f) { Config::instance()->set_reference_filters (f); pair p = Filter::ffmpeg_strings (Config::instance()->reference_filters ()); - _reference_filters->SetLabel (std_to_wx (p.first + " " + p.second)); + _reference_filters->SetLabel (std_to_wx (p.first + N_(" ") + p.second)); } void diff --git a/src/wx/film_editor.cc b/src/wx/film_editor.cc index 68291a812..b328f04c9 100644 --- a/src/wx/film_editor.cc +++ b/src/wx/film_editor.cc @@ -162,7 +162,7 @@ FilmEditor::make_film_panel () _still_duration = new wxSpinCtrl (_film_panel); still_control (_still_duration); s->Add (_still_duration, 1, wxEXPAND); - /* TRANSLATORS: `s' here is an abbreviation for seconds, the unit of time */ + /// TRANSLATORS: `s' here is an abbreviation for seconds, the unit of time still_control (add_label_to_sizer (s, _film_panel, _("s"))); grid->Add (s); } @@ -320,7 +320,7 @@ FilmEditor::make_audio_panel () wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL); _audio_delay = new wxSpinCtrl (_audio_panel); s->Add (video_control (_audio_delay), 1); - /* TRANSLATORS: this is an abbreviation for milliseconds, the unit of time */ + /// TRANSLATORS: this is an abbreviation for milliseconds, the unit of time video_control (add_label_to_sizer (s, _audio_panel, _("ms"))); grid->Add (s); } @@ -342,9 +342,8 @@ FilmEditor::make_audio_panel () assert (MAX_AUDIO_CHANNELS == 6); - /* TRANSLATORS: these are the names of audio channels; Lfe (sub) is the low-frequency - enhancement channel (sub-woofer)./ - */ + /// TRANSLATORS: these are the names of audio channels; Lfe (sub) is the low-frequency + /// enhancement channel (sub-woofer). wxString const channels[] = { _("Left"), _("Right"), @@ -617,9 +616,9 @@ FilmEditor::film_changed (Film::Property p) break; case Film::LENGTH: if (_film->frames_per_second() > 0 && _film->length()) { - s << _film->length().get() << " frames; " << seconds_to_hms (_film->length().get() / _film->frames_per_second()); + s << _film->length().get() << " " << _("frames") << "; " << seconds_to_hms (_film->length().get() / _film->frames_per_second()); } else if (_film->length()) { - s << _film->length().get() << " frames"; + s << _film->length().get() << " " << _("frames"); } _length->SetLabel (std_to_wx (s.str ())); if (_film->length()) { @@ -754,7 +753,7 @@ FilmEditor::set_film (shared_ptr f) if (_film) { FileChanged (_film->directory ()); } else { - FileChanged (""); + FileChanged (N_("")); } film_changed (Film::NAME); @@ -1132,11 +1131,11 @@ FilmEditor::setup_audio_details () } else { stringstream s; if (_film->audio_stream()->channels() == 1) { - s << "1 channel"; + s << _("1 channel"); } else { - s << _film->audio_stream()->channels () << " channels"; + s << _film->audio_stream()->channels () << " " << _("channels"); } - s << ", " << _film->audio_stream()->sample_rate() << "Hz"; + s << ", " << _film->audio_stream()->sample_rate() << _("Hz"); _audio->SetLabel (std_to_wx (s.str ())); } } @@ -1169,7 +1168,7 @@ FilmEditor::setup_dcp_name () { string s = _film->dcp_name (true); if (s.length() > 28) { - _dcp_name->SetLabel (std_to_wx (s.substr (0, 28) + "...")); + _dcp_name->SetLabel (std_to_wx (s.substr (0, 28) + N_("..."))); _dcp_name->SetToolTip (std_to_wx (s)); } else { _dcp_name->SetLabel (std_to_wx (s)); diff --git a/src/wx/film_viewer.cc b/src/wx/film_viewer.cc index 96656ce09..3705f38bb 100644 --- a/src/wx/film_viewer.cc +++ b/src/wx/film_viewer.cc @@ -51,7 +51,7 @@ FilmViewer::FilmViewer (shared_ptr f, wxWindow* p) : wxPanel (p) , _panel (new wxPanel (this)) , _slider (new wxSlider (this, wxID_ANY, 0, 0, 4096)) - , _play_button (new wxToggleButton (this, wxID_ANY, wxT ("Play"))) + , _play_button (new wxToggleButton (this, wxID_ANY, _("Play"))) , _display_frame_x (0) , _got_frame (false) , _clear_required (false) diff --git a/src/wx/properties_dialog.cc b/src/wx/properties_dialog.cc index a57aaf5b9..e93d06dbe 100644 --- a/src/wx/properties_dialog.cc +++ b/src/wx/properties_dialog.cc @@ -54,7 +54,7 @@ PropertiesDialog::PropertiesDialog (wxWindow* parent, shared_ptr film) _frames->SetLabel (std_to_wx (lexical_cast (_film->length().get()))); double const disk = ((double) _film->j2k_bandwidth() / 8) * _film->length().get() / (_film->frames_per_second () * 1073741824); stringstream s; - s << fixed << setprecision (1) << disk << "Gb"; + s << fixed << setprecision (1) << disk << _("Gb"); _disk->SetLabel (std_to_wx (s.str ())); } else { _frames->SetLabel (_("unknown")); diff --git a/src/wx/server_dialog.cc b/src/wx/server_dialog.cc index 1b5b71dc9..46e3f7127 100644 --- a/src/wx/server_dialog.cc +++ b/src/wx/server_dialog.cc @@ -27,7 +27,7 @@ ServerDialog::ServerDialog (wxWindow* parent, ServerDescription* server) if (server) { _server = server; } else { - _server = new ServerDescription ("localhost", 1); + _server = new ServerDescription (N_("localhost"), 1); } wxFlexGridSizer* table = new wxFlexGridSizer (2, 4, 4); diff --git a/wscript b/wscript index edf01784b..16ef91f3b 100644 --- a/wscript +++ b/wscript @@ -21,7 +21,9 @@ def configure(conf): if conf.options.target_windows: conf.load('winres') - conf.env.append_value('CXXFLAGS', ['-D__STDC_CONSTANT_MACROS', '-msse', '-mfpmath=sse', '-ffast-math', '-fno-strict-aliasing', '-Wall', '-Wno-attributes', '-Wextra']) + conf.env.append_value('CXXFLAGS', ['-D__STDC_CONSTANT_MACROS', '-msse', '-mfpmath=sse', '-ffast-math', '-fno-strict-aliasing', + '-Wall', '-Wno-attributes', '-Wextra', + '-DLOCALE_DIR="%s/share/locale"' % conf.env.prefix]) if conf.options.target_windows: conf.env.append_value('CXXFLAGS', ['-DDVDOMATIC_WINDOWS', '-DWIN32_LEAN_AND_MEAN', '-DBOOST_USE_WINDOWS_H', '-DUNICODE']) -- cgit v1.2.3 From bb95f333f15ace7c032bb5b5761b512b6fe2e84e Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Fri, 8 Mar 2013 21:03:28 +0000 Subject: Numerous fixes to A/B mode so that at least it doesn't crash (#72). --- src/lib/ab_transcoder.cc | 17 +++++++++++++---- src/lib/combiner.cc | 2 +- src/lib/combiner.h | 2 +- src/lib/dcp_video_frame.cc | 2 +- src/lib/dcp_video_frame.h | 4 ++-- src/lib/delay_line.cc | 2 +- src/lib/delay_line.h | 2 +- src/lib/film.cc | 9 +++++---- src/lib/film.h | 4 ++-- src/lib/gain.cc | 2 +- src/lib/gain.h | 2 +- src/lib/matcher.cc | 2 +- src/lib/matcher.h | 2 +- src/lib/processor.h | 10 +++++----- src/lib/server.cc | 2 +- src/lib/server.h | 4 ++-- src/lib/transcoder.cc | 1 - src/tools/dvdomatic.cc | 10 +++++++--- src/tools/servomatic_cli.cc | 9 ++++++--- src/tools/servomatic_gui.cc | 13 ++++++++----- src/tools/servomatictest.cc | 6 +++--- test/test.cc | 14 +++++++------- 22 files changed, 70 insertions(+), 51 deletions(-) (limited to 'src/lib/server.cc') diff --git a/src/lib/ab_transcoder.cc b/src/lib/ab_transcoder.cc index 4ed5d02ca..3a1cd83d7 100644 --- a/src/lib/ab_transcoder.cc +++ b/src/lib/ab_transcoder.cc @@ -40,6 +40,7 @@ using std::string; using boost::shared_ptr; +using boost::dynamic_pointer_cast; /** @param a Film to use for the left half of the screen. * @param b Film to use for the right half of the screen. @@ -54,6 +55,7 @@ ABTranscoder::ABTranscoder ( , _film_b (b) , _job (j) , _encoder (e) + , _combiner (new Combiner (a->log())) { _da = decoder_factory (_film_a, o); _db = decoder_factory (_film_b, o); @@ -92,17 +94,24 @@ void ABTranscoder::go () { _encoder->process_begin (); + + bool done[3] = { false, false, false }; while (1) { - bool const va = _da.video->pass (); - bool const vb = _db.video->pass (); - bool const a = _da.audio->pass (); + done[0] = _da.video->pass (); + done[1] = _db.video->pass (); + + if (!done[2] && _da.audio && dynamic_pointer_cast (_da.audio) != dynamic_pointer_cast (_da.video)) { + done[2] = _da.audio->pass (); + } else { + done[2] = true; + } if (_job) { _da.video->set_progress (_job); } - if (va && vb && a) { + if (done[0] && done[1] && done[2]) { break; } } diff --git a/src/lib/combiner.cc b/src/lib/combiner.cc index 68aafd2a2..12ce4a96e 100644 --- a/src/lib/combiner.cc +++ b/src/lib/combiner.cc @@ -22,7 +22,7 @@ using boost::shared_ptr; -Combiner::Combiner (Log* log) +Combiner::Combiner (shared_ptr log) : VideoProcessor (log) { diff --git a/src/lib/combiner.h b/src/lib/combiner.h index 7fad1aeae..68026eaff 100644 --- a/src/lib/combiner.h +++ b/src/lib/combiner.h @@ -31,7 +31,7 @@ class Combiner : public VideoProcessor { public: - Combiner (Log* log); + Combiner (boost::shared_ptr log); void process_video (boost::shared_ptr i, bool, boost::shared_ptr s); void process_video_b (boost::shared_ptr i, bool, boost::shared_ptr s); diff --git a/src/lib/dcp_video_frame.cc b/src/lib/dcp_video_frame.cc index 67617c63c..d735122b5 100644 --- a/src/lib/dcp_video_frame.cc +++ b/src/lib/dcp_video_frame.cc @@ -80,7 +80,7 @@ using libdcp::Size; 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, string pp, int clut, int bw, Log* l + Scaler const * s, int f, int dcp_fps, string pp, int clut, int bw, shared_ptr l ) : _input (yuv) , _subtitle (sub) diff --git a/src/lib/dcp_video_frame.h b/src/lib/dcp_video_frame.h index 6794765ac..4ceb07d26 100644 --- a/src/lib/dcp_video_frame.h +++ b/src/lib/dcp_video_frame.h @@ -107,7 +107,7 @@ class DCPVideoFrame public: DCPVideoFrame ( boost::shared_ptr, boost::shared_ptr, libdcp::Size, - int, int, float, Scaler const *, int, int, std::string, int, int, Log * + int, int, float, Scaler const *, int, int, std::string, int, int, boost::shared_ptr ); virtual ~DCPVideoFrame (); @@ -135,7 +135,7 @@ private: int _colour_lut; ///< Colour look-up table to use int _j2k_bandwidth; ///< J2K bandwidth to use - Log* _log; ///< log + boost::shared_ptr _log; ///< log opj_image_cmptparm_t _cmptparm[3]; ///< libopenjpeg's opj_image_cmptparm_t opj_image* _image; ///< libopenjpeg's image container diff --git a/src/lib/delay_line.cc b/src/lib/delay_line.cc index 4ad172781..53da9a412 100644 --- a/src/lib/delay_line.cc +++ b/src/lib/delay_line.cc @@ -30,7 +30,7 @@ using boost::shared_ptr; /** @param channels Number of channels of audio. * @param frames Delay in frames, +ve to move audio later. */ -DelayLine::DelayLine (Log* log, int channels, int frames) +DelayLine::DelayLine (shared_ptr log, int channels, int frames) : AudioProcessor (log) , _negative_delay_remaining (0) , _frames (frames) diff --git a/src/lib/delay_line.h b/src/lib/delay_line.h index 4d6f1313b..c51784f35 100644 --- a/src/lib/delay_line.h +++ b/src/lib/delay_line.h @@ -26,7 +26,7 @@ class AudioBuffers; class DelayLine : public AudioProcessor { public: - DelayLine (Log* log, int channels, int frames); + DelayLine (boost::shared_ptr log, int channels, int frames); void process_audio (boost::shared_ptr); diff --git a/src/lib/film.cc b/src/lib/film.cc index 20e08c037..8028f40ef 100644 --- a/src/lib/film.cc +++ b/src/lib/film.cc @@ -144,12 +144,13 @@ Film::Film (string d, bool must_exist) read_metadata (); } - _log = new FileLog (file ("log")); + _log.reset (new FileLog (file ("log"))); } Film::Film (Film const & o) : boost::enable_shared_from_this (o) - , _log (0) + /* note: the copied film shares the original's log */ + , _log (o._log) , _directory (o._directory) , _name (o._name) , _use_dci_name (o._use_dci_name) @@ -188,12 +189,12 @@ Film::Film (Film const & o) , _source_frame_rate (o._source_frame_rate) , _dirty (o._dirty) { - + } Film::~Film () { - delete _log; + } string diff --git a/src/lib/film.h b/src/lib/film.h index 88f6fbcd7..2ab4a9450 100644 --- a/src/lib/film.h +++ b/src/lib/film.h @@ -77,7 +77,7 @@ public: /** @return Logger. * It is safe to call this from any thread. */ - Log* log () const { + boost::shared_ptr log () const { return _log; } @@ -382,7 +382,7 @@ public: private: /** Log to write to */ - Log* _log; + boost::shared_ptr _log; /** Any running ExamineContentJob, or 0 */ boost::shared_ptr _examine_content_job; diff --git a/src/lib/gain.cc b/src/lib/gain.cc index cec3b3c62..df7011d2e 100644 --- a/src/lib/gain.cc +++ b/src/lib/gain.cc @@ -22,7 +22,7 @@ using boost::shared_ptr; /** @param gain gain in dB */ -Gain::Gain (Log* log, float gain) +Gain::Gain (shared_ptr log, float gain) : AudioProcessor (log) , _gain (gain) { diff --git a/src/lib/gain.h b/src/lib/gain.h index 716ee9b51..d462e5aee 100644 --- a/src/lib/gain.h +++ b/src/lib/gain.h @@ -22,7 +22,7 @@ class Gain : public AudioProcessor { public: - Gain (Log* log, float gain); + Gain (boost::shared_ptr log, float gain); void process_audio (boost::shared_ptr); diff --git a/src/lib/matcher.cc b/src/lib/matcher.cc index 4cd264338..48f6ed912 100644 --- a/src/lib/matcher.cc +++ b/src/lib/matcher.cc @@ -26,7 +26,7 @@ using std::min; using boost::shared_ptr; -Matcher::Matcher (Log* log, int sample_rate, float frames_per_second) +Matcher::Matcher (shared_ptr log, int sample_rate, float frames_per_second) : AudioVideoProcessor (log) , _sample_rate (sample_rate) , _frames_per_second (frames_per_second) diff --git a/src/lib/matcher.h b/src/lib/matcher.h index 60bb87432..b1680e131 100644 --- a/src/lib/matcher.h +++ b/src/lib/matcher.h @@ -24,7 +24,7 @@ class Matcher : public AudioVideoProcessor { public: - Matcher (Log* log, int sample_rate, float frames_per_second); + Matcher (boost::shared_ptr log, int sample_rate, float frames_per_second); void process_video (boost::shared_ptr i, bool, boost::shared_ptr s); void process_audio (boost::shared_ptr); void process_end (); diff --git a/src/lib/processor.h b/src/lib/processor.h index 19d7c4b0c..1ba396f2f 100644 --- a/src/lib/processor.h +++ b/src/lib/processor.h @@ -40,7 +40,7 @@ public: /** Construct a Processor. * @param log Log to use. */ - Processor (Log* log) + Processor (boost::shared_ptr log) : _log (log) {} @@ -50,7 +50,7 @@ public: virtual void process_end () {} protected: - Log* _log; ///< log to write to + boost::shared_ptr _log; ///< log to write to }; /** @class AudioVideoProcessor @@ -62,7 +62,7 @@ public: /** Construct an AudioVideoProcessor. * @param log Log to write to. */ - AudioVideoProcessor (Log* log) + AudioVideoProcessor (boost::shared_ptr log) : Processor (log) {} }; @@ -76,7 +76,7 @@ public: /** Construct an AudioProcessor. * @param log Log to write to. */ - AudioProcessor (Log* log) + AudioProcessor (boost::shared_ptr log) : Processor (log) {} }; @@ -90,7 +90,7 @@ public: /** Construct an VideoProcessor. * @param log Log to write to. */ - VideoProcessor (Log* log) + VideoProcessor (boost::shared_ptr log) : Processor (log) {} }; diff --git a/src/lib/server.cc b/src/lib/server.cc index 76a25bfbb..9c5a77f68 100644 --- a/src/lib/server.cc +++ b/src/lib/server.cc @@ -77,7 +77,7 @@ ServerDescription::as_metadata () const return s.str (); } -Server::Server (Log* log) +Server::Server (shared_ptr log) : _log (log) { diff --git a/src/lib/server.h b/src/lib/server.h index 32ba8dc4b..89aeca626 100644 --- a/src/lib/server.h +++ b/src/lib/server.h @@ -76,7 +76,7 @@ private: class Server { public: - Server (Log* log); + Server (boost::shared_ptr log); void run (int num_threads); @@ -88,5 +88,5 @@ private: std::list > _queue; boost::mutex _worker_mutex; boost::condition _worker_condition; - Log* _log; + boost::shared_ptr _log; }; diff --git a/src/lib/transcoder.cc b/src/lib/transcoder.cc index 9720ca56a..e0f3a03a2 100644 --- a/src/lib/transcoder.cc +++ b/src/lib/transcoder.cc @@ -38,7 +38,6 @@ #include "audio_decoder.h" using std::string; -using std::cout; using boost::shared_ptr; using boost::dynamic_pointer_cast; diff --git a/src/tools/dvdomatic.cc b/src/tools/dvdomatic.cc index 4874e6ef8..230e02c88 100644 --- a/src/tools/dvdomatic.cc +++ b/src/tools/dvdomatic.cc @@ -482,12 +482,16 @@ class App : public wxApp #ifdef DVDOMATIC_POSIX unsetenv ("UBUNTU_MENUPROXY"); #endif - + + /* This needs to be before setup_i18n, as setup_i18n() will + create a Config object, which needs Scalers to have + been created. + */ + dvdomatic_setup (); + wxInitAllImageHandlers (); setup_i18n (); - dvdomatic_setup (); - if (!film_to_load.empty() && boost::filesystem::is_directory (film_to_load)) { try { film.reset (new Film (film_to_load)); diff --git a/src/tools/servomatic_cli.cc b/src/tools/servomatic_cli.cc index f8e713193..6626d45b9 100644 --- a/src/tools/servomatic_cli.cc +++ b/src/tools/servomatic_cli.cc @@ -42,7 +42,10 @@ #include "log.h" #include "version.h" -using namespace std; +using std::cerr; +using std::string; +using std::cout; +using boost::shared_ptr; static void help (string n) @@ -87,8 +90,8 @@ main (int argc, char* argv[]) } Scaler::setup_scalers (); - FileLog log ("servomatic.log"); - Server server (&log); + shared_ptr log (new FileLog ("servomatic.log")); + Server server (log); server.run (num_threads); return 0; } diff --git a/src/tools/servomatic_gui.cc b/src/tools/servomatic_gui.cc index 610ba8005..dd169725f 100644 --- a/src/tools/servomatic_gui.cc +++ b/src/tools/servomatic_gui.cc @@ -25,8 +25,11 @@ #include "lib/server.h" #include "lib/config.h" -using namespace std; -using namespace boost; +using std::cout; +using std::string; +using boost::shared_ptr; +using boost::thread; +using boost::bind; enum { ID_status = 1, @@ -52,7 +55,7 @@ private: string _log; }; -static MemoryLog memory_log; +static shared_ptr memory_log (new MemoryLog); class StatusDialog : public wxDialog { @@ -77,7 +80,7 @@ public: private: void update (wxTimerEvent &) { - _text->ChangeValue (std_to_wx (memory_log.get ())); + _text->ChangeValue (std_to_wx (memory_log->get ())); _sizer->Layout (); } @@ -141,7 +144,7 @@ private: void main_thread () { - Server server (&memory_log); + Server server (memory_log); server.run (Config::instance()->num_local_encoding_threads ()); } diff --git a/src/tools/servomatictest.cc b/src/tools/servomatictest.cc index 91ad02120..f5756c693 100644 --- a/src/tools/servomatictest.cc +++ b/src/tools/servomatictest.cc @@ -43,7 +43,7 @@ using std::pair; using boost::shared_ptr; static ServerDescription* server; -static FileLog log_ ("servomatictest.log"); +static shared_ptr log_ (new FileLog ("servomatictest.log")); static int frame = 0; void @@ -53,14 +53,14 @@ process_video (shared_ptr image, bool, shared_ptr sub) new DCPVideoFrame ( image, sub, libdcp::Size (1024, 1024), 0, 0, 0, - Scaler::from_id ("bicubic"), frame, 24, "", 0, 250000000, &log_) + Scaler::from_id ("bicubic"), frame, 24, "", 0, 250000000, log_) ); shared_ptr remote ( new DCPVideoFrame ( image, sub, libdcp::Size (1024, 1024), 0, 0, 0, - Scaler::from_id ("bicubic"), frame, 24, "", 0, 250000000, &log_) + Scaler::from_id ("bicubic"), frame, 24, "", 0, 250000000, log_) ); cout << "Frame " << frame << ": "; diff --git a/test/test.cc b/test/test.cc index 15c34ca78..448168f24 100644 --- a/test/test.cc +++ b/test/test.cc @@ -254,9 +254,9 @@ public: void do_positive_delay_line_test (int delay_length, int data_length) { - NullLog log; + shared_ptr log (new NullLog); - DelayLine d (&log, 6, delay_length); + DelayLine d (log, 6, delay_length); shared_ptr data (new AudioBuffers (6, data_length)); int in = 0; @@ -297,9 +297,9 @@ do_positive_delay_line_test (int delay_length, int data_length) void do_negative_delay_line_test (int delay_length, int data_length) { - NullLog log; + shared_ptr log (new NullLog); - DelayLine d (&log, 6, delay_length); + DelayLine d (log, 6, delay_length); shared_ptr data (new AudioBuffers (6, data_length)); int in = 0; @@ -406,7 +406,7 @@ BOOST_AUTO_TEST_CASE (client_server_test) shared_ptr subtitle (new Subtitle (Position (50, 60), sub_image)); - FileLog log ("build/test/client_server_test.log"); + shared_ptr log (new FileLog ("build/test/client_server_test.log")); shared_ptr frame ( new DCPVideoFrame ( @@ -422,14 +422,14 @@ BOOST_AUTO_TEST_CASE (client_server_test) "", 0, 200000000, - &log + log ) ); shared_ptr locally_encoded = frame->encode_locally (); BOOST_ASSERT (locally_encoded); - Server* server = new Server (&log); + Server* server = new Server (log); new thread (boost::bind (&Server::run, server, 2)); -- cgit v1.2.3 From b468ccabdb13fca86ae8a324239d83490ef5832e Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Mon, 1 Apr 2013 02:25:02 +0100 Subject: XML metadata and some other bits. --- src/lib/ab_transcoder.h | 1 - src/lib/audio_content.cc | 9 ++ src/lib/audio_content.h | 5 + src/lib/config.cc | 89 ++++++++++--- src/lib/config.h | 3 +- src/lib/content.cc | 16 +++ src/lib/content.h | 7 + src/lib/dci_metadata.cc | 33 +++-- src/lib/dci_metadata.h | 12 +- src/lib/decoder_factory.cc | 43 ------ src/lib/decoder_factory.h | 47 ------- src/lib/ffmpeg_content.cc | 86 ++++++++++++ src/lib/ffmpeg_content.h | 10 ++ src/lib/film.cc | 293 +++++++++++++++-------------------------- src/lib/film.h | 10 +- src/lib/imagemagick_content.cc | 9 ++ src/lib/imagemagick_content.h | 5 + src/lib/server.cc | 23 ++-- src/lib/server.h | 9 +- src/lib/sndfile_content.cc | 11 +- src/lib/sndfile_content.h | 5 + src/lib/transcoder.cc | 1 - src/lib/transcoder.h | 2 - src/lib/video_content.cc | 22 ++++ src/lib/video_content.h | 3 + src/lib/wscript | 3 +- src/tools/makedcp.cc | 2 +- src/tools/servomatictest.cc | 13 +- src/wx/audio_plot.cc | 1 - src/wx/film_editor.cc | 18 +-- src/wx/film_editor.h | 4 +- src/wx/film_viewer.h | 1 - test/test.cc | 4 +- 33 files changed, 443 insertions(+), 357 deletions(-) delete mode 100644 src/lib/decoder_factory.cc delete mode 100644 src/lib/decoder_factory.h (limited to 'src/lib/server.cc') diff --git a/src/lib/ab_transcoder.h b/src/lib/ab_transcoder.h index 090c26fb7..5ce4a03da 100644 --- a/src/lib/ab_transcoder.h +++ b/src/lib/ab_transcoder.h @@ -25,7 +25,6 @@ #include #include #include "util.h" -#include "decoder_factory.h" class Job; class Encoder; diff --git a/src/lib/audio_content.cc b/src/lib/audio_content.cc index e9eacfd79..74b8ea2ce 100644 --- a/src/lib/audio_content.cc +++ b/src/lib/audio_content.cc @@ -1,7 +1,16 @@ +#include #include "audio_content.h" +using boost::shared_ptr; + AudioContent::AudioContent (boost::filesystem::path f) : Content (f) { } + +AudioContent::AudioContent (shared_ptr node) + : Content (node) +{ + +} diff --git a/src/lib/audio_content.h b/src/lib/audio_content.h index e18d1082e..f3dd81efb 100644 --- a/src/lib/audio_content.h +++ b/src/lib/audio_content.h @@ -4,10 +4,15 @@ #include "content.h" #include "util.h" +namespace cxml { + class Node; +} + class AudioContent : public virtual Content { public: AudioContent (boost::filesystem::path); + AudioContent (boost::shared_ptr); virtual int audio_channels () const = 0; virtual ContentAudioFrame audio_length () const = 0; diff --git a/src/lib/config.cc b/src/lib/config.cc index 5dce3748d..2defa0539 100644 --- a/src/lib/config.cc +++ b/src/lib/config.cc @@ -22,6 +22,7 @@ #include #include #include +#include #include "config.h" #include "server.h" #include "scaler.h" @@ -34,7 +35,9 @@ using std::vector; using std::ifstream; using std::string; using std::ofstream; +using std::list; using boost::shared_ptr; +using boost::optional; Config* Config::_instance = 0; @@ -52,8 +55,51 @@ Config::Config () _allowed_dcp_frame_rates.push_back (48); _allowed_dcp_frame_rates.push_back (50); _allowed_dcp_frame_rates.push_back (60); + + if (!boost::filesystem::exists (file (false))) { + read_old_metadata (); + return; + } + + cxml::File f (file (false), "Config"); + optional c; + + _num_local_encoding_threads = f.number_child ("NumLocalEncodingThreads"); + _default_directory = f.string_child ("DefaultDirectory"); + _server_port = f.number_child ("ServerPort"); + c = f.optional_string_child ("ReferenceScaler"); + if (c) { + _reference_scaler = Scaler::from_id (c.get ()); + } + + list > filters = f.node_children ("ReferenceFilter"); + for (list >::iterator i = filters.begin(); i != filters.end(); ++i) { + _reference_filters.push_back (Filter::from_id ((*i)->content ())); + } - ifstream f (file().c_str ()); + list > servers = f.node_children ("Server"); + for (list >::iterator i = servers.begin(); i != servers.end(); ++i) { + _servers.push_back (new ServerDescription (*i)); + } + + _tms_ip = f.string_child ("TMSIP"); + _tms_path = f.string_child ("TMSPath"); + _tms_user = f.string_child ("TMSUser"); + _tms_password = f.string_child ("TMSPassword"); + + c = f.optional_string_child ("SoundProcessor"); + if (c) { + _sound_processor = SoundProcessor::from_id (c.get ()); + } + + _language = f.optional_string_child ("Language"); + _default_dci_metadata = DCIMetadata (f.node_child ("DCIMetadata")); +} + +void +Config::read_old_metadata () +{ + ifstream f (file(true).c_str ()); string line; while (getline (f, line)) { if (line.empty ()) { @@ -98,17 +144,21 @@ Config::Config () _language = v; } - _default_dci_metadata.read (k, v); + _default_dci_metadata.read_old_metadata (k, v); } } /** @return Filename to write configuration to */ string -Config::file () const +Config::file (bool old) const { boost::filesystem::path p; p /= g_get_user_config_dir (); - p /= N_(".dvdomatic"); + if (old) { + p /= ".dvdomatic"; + } else { + p /= ".dvdomatic.xml"; + } return p.string (); } @@ -127,35 +177,38 @@ Config::instance () void Config::write () const { - ofstream f (file().c_str ()); - f << N_("num_local_encoding_threads ") << _num_local_encoding_threads << N_("\n") - << N_("default_directory ") << _default_directory << N_("\n") - << N_("server_port ") << _server_port << N_("\n"); + xmlpp::Document doc; + xmlpp::Element* root = doc.create_root_node ("Config"); + root->add_child("NumLocalEncodingThreads")->add_child_text (boost::lexical_cast (_num_local_encoding_threads)); + root->add_child("DefaultDirectory")->add_child_text (_default_directory); + root->add_child("ServerPort")->add_child_text (boost::lexical_cast (_server_port)); if (_reference_scaler) { - f << "reference_scaler " << _reference_scaler->id () << "\n"; + root->add_child("ReferenceScaler")->add_child_text (_reference_scaler->id ()); } for (vector::const_iterator i = _reference_filters.begin(); i != _reference_filters.end(); ++i) { - f << N_("reference_filter ") << (*i)->id () << N_("\n"); + root->add_child("ReferenceFilter")->add_child_text ((*i)->id ()); } for (vector::const_iterator i = _servers.begin(); i != _servers.end(); ++i) { - f << N_("server ") << (*i)->as_metadata () << N_("\n"); + (*i)->as_xml (root->add_child ("Server")); } - f << N_("tms_ip ") << _tms_ip << N_("\n"); - f << N_("tms_path ") << _tms_path << N_("\n"); - f << N_("tms_user ") << _tms_user << N_("\n"); - f << N_("tms_password ") << _tms_password << N_("\n"); + root->add_child("TMSIP")->add_child_text (_tms_ip); + root->add_child("TMSPath")->add_child_text (_tms_path); + root->add_child("TMSUser")->add_child_text (_tms_user); + root->add_child("TMSPassword")->add_child_text (_tms_password); if (_sound_processor) { - f << "sound_processor " << _sound_processor->id () << "\n"; + root->add_child("SoundProcessor")->add_child_text (_sound_processor->id ()); } if (_language) { - f << "language " << _language.get() << "\n"; + root->add_child("Language")->add_child_text (_language.get()); } - _default_dci_metadata.write (f); + _default_dci_metadata.as_xml (root->add_child ("DCIMetadata")); + + doc.write_to_file_formatted (file (false)); } string diff --git a/src/lib/config.h b/src/lib/config.h index 011ca716f..13d36d236 100644 --- a/src/lib/config.h +++ b/src/lib/config.h @@ -177,7 +177,8 @@ public: private: Config (); - std::string file () const; + std::string file (bool) const; + void read_old_metadata (); /** number of threads to use for J2K encoding on the local machine */ int _num_local_encoding_threads; diff --git a/src/lib/content.cc b/src/lib/content.cc index 2fb94e959..977f2e2a7 100644 --- a/src/lib/content.cc +++ b/src/lib/content.cc @@ -1,4 +1,6 @@ #include +#include +#include #include "content.h" #include "util.h" @@ -11,6 +13,20 @@ Content::Content (boost::filesystem::path f) } +Content::Content (shared_ptr node) +{ + _file = node->string_child ("File"); + _digest = node->string_child ("Digest"); +} + +void +Content::as_xml (xmlpp::Node* node) const +{ + boost::mutex::scoped_lock lm (_mutex); + node->add_child("File")->add_child_text (_file.string()); + node->add_child("Digest")->add_child_text (_digest); +} + void Content::examine (shared_ptr, shared_ptr, bool) { diff --git a/src/lib/content.h b/src/lib/content.h index 25c097424..3a94d2297 100644 --- a/src/lib/content.h +++ b/src/lib/content.h @@ -4,6 +4,11 @@ #include #include #include +#include + +namespace cxml { + class Node; +} class Job; class Film; @@ -12,9 +17,11 @@ class Content { public: Content (boost::filesystem::path); + Content (boost::shared_ptr); virtual void examine (boost::shared_ptr, boost::shared_ptr, bool); virtual std::string summary () const = 0; + virtual void as_xml (xmlpp::Node *) const; boost::filesystem::path file () const { boost::mutex::scoped_lock lm (_mutex); diff --git a/src/lib/dci_metadata.cc b/src/lib/dci_metadata.cc index 758886db4..f25b3ddb0 100644 --- a/src/lib/dci_metadata.cc +++ b/src/lib/dci_metadata.cc @@ -18,26 +18,39 @@ */ #include +#include #include "dci_metadata.h" #include "i18n.h" -using namespace std; +using std::string; +using boost::shared_ptr; + +DCIMetadata::DCIMetadata (shared_ptr node) +{ + audio_language = node->string_child ("AudioLanguage"); + subtitle_language = node->string_child ("SubtitleLanguage"); + territory = node->string_child ("Territory"); + rating = node->string_child ("Rating"); + studio = node->string_child ("Studio"); + facility = node->string_child ("Facility"); + package_type = node->string_child ("PackageType"); +} void -DCIMetadata::write (ostream& f) const +DCIMetadata::as_xml (xmlpp::Node* root) const { - f << N_("audio_language ") << audio_language << N_("\n"); - f << N_("subtitle_language ") << subtitle_language << N_("\n"); - f << N_("territory ") << territory << N_("\n"); - f << N_("rating ") << rating << N_("\n"); - f << N_("studio ") << studio << N_("\n"); - f << N_("facility ") << facility << N_("\n"); - f << N_("package_type ") << package_type << N_("\n"); + root->add_child("AudioLanguage")->add_child_text (audio_language); + root->add_child("SubtitleLanguage")->add_child_text (subtitle_language); + root->add_child("Territory")->add_child_text (territory); + root->add_child("Rating")->add_child_text (rating); + root->add_child("Studio")->add_child_text (studio); + root->add_child("Facility")->add_child_text (facility); + root->add_child("PackageType")->add_child_text (package_type); } void -DCIMetadata::read (string k, string v) +DCIMetadata::read_old_metadata (string k, string v) { if (k == N_("audio_language")) { audio_language = v; diff --git a/src/lib/dci_metadata.h b/src/lib/dci_metadata.h index eecdc7655..f61dae5a8 100644 --- a/src/lib/dci_metadata.h +++ b/src/lib/dci_metadata.h @@ -21,12 +21,20 @@ #define DVDOMATIC_DCI_METADATA_H #include +#include + +namespace cxml { + class Node; +} class DCIMetadata { public: - void read (std::string, std::string); - void write (std::ostream &) const; + DCIMetadata () {} + DCIMetadata (boost::shared_ptr); + + void as_xml (xmlpp::Node *) const; + void read_old_metadata (std::string, std::string); std::string audio_language; std::string subtitle_language; diff --git a/src/lib/decoder_factory.cc b/src/lib/decoder_factory.cc deleted file mode 100644 index 7940edc2e..000000000 --- a/src/lib/decoder_factory.cc +++ /dev/null @@ -1,43 +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/decoder_factory.cc - * @brief A method to create an appropriate decoder for some content. - */ - -#include -#include "ffmpeg_decoder.h" -#include "imagemagick_decoder.h" -#include "film.h" -#include "sndfile_decoder.h" -#include "decoder_factory.h" - -using std::string; -using std::pair; -using std::make_pair; -using boost::shared_ptr; -using boost::dynamic_pointer_cast; - -Decoders -decoder_factory ( - shared_ptr f - ) -{ - return Decoders (); -} diff --git a/src/lib/decoder_factory.h b/src/lib/decoder_factory.h deleted file mode 100644 index 3fd91f876..000000000 --- a/src/lib/decoder_factory.h +++ /dev/null @@ -1,47 +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. - -*/ - -#ifndef DVDOMATIC_DECODER_FACTORY_H -#define DVDOMATIC_DECODER_FACTORY_H - -/** @file src/decoder_factory.h - * @brief A method to create appropriate decoders for some content. - */ - -class Film; -class VideoDecoder; -class AudioDecoder; - -struct Decoders { - Decoders () {} - - Decoders (boost::shared_ptr v, boost::shared_ptr a) - : video (v) - , audio (a) - {} - - boost::shared_ptr video; - boost::shared_ptr audio; -}; - -extern Decoders decoder_factory ( - boost::shared_ptr - ); - -#endif diff --git a/src/lib/ffmpeg_content.cc b/src/lib/ffmpeg_content.cc index 6109b7212..42e04e838 100644 --- a/src/lib/ffmpeg_content.cc +++ b/src/lib/ffmpeg_content.cc @@ -1,3 +1,4 @@ +#include #include "ffmpeg_content.h" #include "ffmpeg_decoder.h" #include "compose.hpp" @@ -8,7 +9,10 @@ #include "i18n.h" using std::string; +using std::vector; +using std::list; using boost::shared_ptr; +using boost::lexical_cast; int const FFmpegContentProperty::SUBTITLE_STREAMS = 100; int const FFmpegContentProperty::SUBTITLE_STREAM = 101; @@ -23,6 +27,54 @@ FFmpegContent::FFmpegContent (boost::filesystem::path f) } +FFmpegContent::FFmpegContent (shared_ptr node) + : Content (node) + , VideoContent (node) + , AudioContent (node) +{ + list > c = node->node_children ("SubtitleStream"); + for (list >::const_iterator i = c.begin(); i != c.end(); ++i) { + _subtitle_streams.push_back (FFmpegSubtitleStream (*i)); + if ((*i)->optional_number_child ("Selected")) { + _subtitle_stream = _subtitle_streams.back (); + } + } + + c = node->node_children ("AudioStream"); + for (list >::const_iterator i = c.begin(); i != c.end(); ++i) { + _audio_streams.push_back (FFmpegAudioStream (*i)); + if ((*i)->optional_number_child ("Selected")) { + _audio_stream = _audio_streams.back (); + } + } +} + +void +FFmpegContent::as_xml (xmlpp::Node* node) const +{ + node->add_child("Type")->add_child_text ("FFmpeg"); + Content::as_xml (node); + VideoContent::as_xml (node); + + boost::mutex::scoped_lock lm (_mutex); + + for (vector::const_iterator i = _subtitle_streams.begin(); i != _subtitle_streams.end(); ++i) { + xmlpp::Node* t = node->add_child("SubtitleStream"); + if (_subtitle_stream && *i == _subtitle_stream.get()) { + t->add_child("Selected")->add_child_text("1"); + } + i->as_xml (t); + } + + for (vector::const_iterator i = _audio_streams.begin(); i != _audio_streams.end(); ++i) { + xmlpp::Node* t = node->add_child("AudioStream"); + if (_audio_stream && *i == _audio_stream.get()) { + t->add_child("Selected")->add_child_text("1"); + } + i->as_xml (t); + } +} + void FFmpegContent::examine (shared_ptr film, shared_ptr job, bool quick) { @@ -151,3 +203,37 @@ operator== (FFmpegAudioStream const & a, FFmpegAudioStream const & b) { return a.id == b.id; } + +FFmpegAudioStream::FFmpegAudioStream (shared_ptr node) +{ + name = node->string_child ("Name"); + id = node->number_child ("Id"); + frame_rate = node->number_child ("FrameRate"); + channel_layout = node->number_child ("ChannelLayout"); +} + +void +FFmpegAudioStream::as_xml (xmlpp::Node* root) const +{ + root->add_child("Name")->add_child_text (name); + root->add_child("Id")->add_child_text (lexical_cast (id)); + root->add_child("FrameRate")->add_child_text (lexical_cast (frame_rate)); + root->add_child("ChannelLayout")->add_child_text (lexical_cast (channel_layout)); +} + +/** Construct a SubtitleStream from a value returned from to_string(). + * @param t String returned from to_string(). + * @param v State file version. + */ +FFmpegSubtitleStream::FFmpegSubtitleStream (shared_ptr node) +{ + name = node->string_child ("Name"); + id = node->number_child ("Id"); +} + +void +FFmpegSubtitleStream::as_xml (xmlpp::Node* root) const +{ + root->add_child("Name")->add_child_text (name); + root->add_child("Id")->add_child_text (lexical_cast (id)); +} diff --git a/src/lib/ffmpeg_content.h b/src/lib/ffmpeg_content.h index 83474ea66..95e24b7b3 100644 --- a/src/lib/ffmpeg_content.h +++ b/src/lib/ffmpeg_content.h @@ -15,6 +15,10 @@ public: , channel_layout (c) {} + FFmpegAudioStream (boost::shared_ptr); + + void as_xml (xmlpp::Node *) const; + int channels () const { return av_get_channel_layout_nb_channels (channel_layout); } @@ -35,6 +39,10 @@ public: , id (i) {} + FFmpegSubtitleStream (boost::shared_ptr); + + void as_xml (xmlpp::Node *) const; + std::string name; int id; }; @@ -54,9 +62,11 @@ class FFmpegContent : public VideoContent, public AudioContent, public boost::en { public: FFmpegContent (boost::filesystem::path); + FFmpegContent (boost::shared_ptr); void examine (boost::shared_ptr, boost::shared_ptr, bool); std::string summary () const; + void as_xml (xmlpp::Node *) const; /* AudioContent */ int audio_channels () const; diff --git a/src/lib/film.cc b/src/lib/film.cc index d22f67e67..a6a53b3fc 100644 --- a/src/lib/film.cc +++ b/src/lib/film.cc @@ -29,6 +29,8 @@ #include #include #include +#include +#include #include "film.h" #include "format.h" #include "job.h" @@ -43,7 +45,6 @@ #include "exceptions.h" #include "examine_content_job.h" #include "scaler.h" -#include "decoder_factory.h" #include "config.h" #include "version.h" #include "ui_signaller.h" @@ -52,6 +53,9 @@ #include "sndfile_decoder.h" #include "analyse_audio_job.h" #include "playlist.h" +#include "ffmpeg_content.h" +#include "imagemagick_content.h" +#include "sndfile_content.h" #include "i18n.h" @@ -67,6 +71,7 @@ using std::setfill; using std::min; using std::make_pair; using std::endl; +using std::list; using boost::shared_ptr; using boost::lexical_cast; using boost::to_upper_copy; @@ -93,7 +98,7 @@ Film::Film (string d, bool must_exist) , _scaler (Scaler::from_id ("bicubic")) , _trim_start (0) , _trim_end (0) - , _dcp_ab (false) + , _ab (false) , _audio_gain (0) , _audio_delay (0) , _with_subtitles (false) @@ -157,7 +162,7 @@ Film::Film (Film const & o) , _scaler (o._scaler) , _trim_start (o._trim_start) , _trim_end (o._trim_end) - , _dcp_ab (o._dcp_ab) + , _ab (o._ab) , _audio_gain (o._audio_gain) , _audio_delay (o._audio_delay) , _with_subtitles (o._with_subtitles) @@ -199,7 +204,7 @@ Film::video_state_identifier () const << "_" << j2k_bandwidth() << "_" << boost::lexical_cast (colour_lut()); - if (dcp_ab()) { + if (ab()) { pair fa = Filter::ffmpeg_strings (Config::instance()->reference_filters()); s << "ab_" << Config::instance()->reference_scaler()->id() << "_" << fa.first << "_" << fa.second; } @@ -297,7 +302,7 @@ Film::make_dcp () shared_ptr r; - if (dcp_ab()) { + if (ab()) { r = JobManager::instance()->add (shared_ptr (new ABTranscodeJob (shared_from_this()))); } else { r = JobManager::instance()->add (shared_ptr (new TranscodeJob (shared_from_this()))); @@ -375,77 +380,54 @@ Film::encoded_frames () const void Film::write_metadata () const { + ContentList the_content = content (); + boost::mutex::scoped_lock lm (_state_mutex); boost::filesystem::create_directories (directory()); - string const m = file ("metadata"); - ofstream f (m.c_str ()); - if (!f.good ()) { - throw CreateFileError (m); - } - - f << "version " << state_version << endl; + xmlpp::Document doc; + xmlpp::Element* root = doc.create_root_node ("Metadata"); - /* User stuff */ - f << "name " << _name << endl; - f << "use_dci_name " << _use_dci_name << endl; -// f << "content " << _content << endl; - f << "trust_content_headers " << (_trust_content_headers ? "1" : "0") << endl; + root->add_child("Version")->add_child_text (boost::lexical_cast (state_version)); + root->add_child("Name")->add_child_text (_name); + root->add_child("UseDCIName")->add_child_text (_use_dci_name ? "1" : "0"); + root->add_child("TrustContentHeaders")->add_child_text (_trust_content_headers ? "1" : "0"); if (_dcp_content_type) { - f << "dcp_content_type " << _dcp_content_type->dci_name () << endl; + root->add_child("DCPContentType")->add_child_text (_dcp_content_type->dci_name ()); } if (_format) { - f << "format " << _format->as_metadata () << endl; + root->add_child("Format")->add_child_text (_format->id ()); } - f << "left_crop " << _crop.left << endl; - f << "right_crop " << _crop.right << endl; - f << "top_crop " << _crop.top << endl; - f << "bottom_crop " << _crop.bottom << endl; - for (vector::const_iterator i = _filters.begin(); i != _filters.end(); ++i) { - f << "filter " << (*i)->id () << endl; - } - f << "scaler " << _scaler->id () << endl; - f << "trim_start " << _trim_start << endl; - f << "trim_end " << _trim_end << endl; - f << "dcp_ab " << (_dcp_ab ? "1" : "0") << endl; -// if (_content_audio_stream) { -// f << "selected_content_audio_stream " << _content_audio_stream->to_string() << endl; -// } -// for (vector::const_iterator i = _external_audio.begin(); i != _external_audio.end(); ++i) { -// f << "external_audio " << *i << endl; -// } -// f << "use_content_audio " << (_use_content_audio ? "1" : "0") << endl; - f << "audio_gain " << _audio_gain << endl; - f << "audio_delay " << _audio_delay << endl; -// f << "still_duration " << _still_duration << endl; -// if (_subtitle_stream) { -// f << "selected_subtitle_stream " << _subtitle_stream->to_string() << endl; -// } - f << "with_subtitles " << _with_subtitles << endl; - f << "subtitle_offset " << _subtitle_offset << endl; - f << "subtitle_scale " << _subtitle_scale << endl; - f << "colour_lut " << _colour_lut << endl; - f << "j2k_bandwidth " << _j2k_bandwidth << endl; - _dci_metadata.write (f); - f << "dci_date " << boost::gregorian::to_iso_string (_dci_date) << endl; - f << "dcp_frame_rate " << _dcp_frame_rate << endl; -// f << "width " << _size.width << endl; -// f << "height " << _size.height << endl; -// f << "length " << _length.get_value_or(0) << endl; -// f << "content_digest " << _content_digest << endl; - -// for (vector >::const_iterator i = _content_audio_streams.begin(); i != _content_audio_streams.end(); ++i) { -// f << "content_audio_stream " << (*i)->to_string () << endl; -// } - -// f << "external_audio_stream " << _sndfile_stream->to_string() << endl; + root->add_child("LeftCrop")->add_child_text (boost::lexical_cast (_crop.left)); + root->add_child("RightCrop")->add_child_text (boost::lexical_cast (_crop.right)); + root->add_child("TopCrop")->add_child_text (boost::lexical_cast (_crop.top)); + root->add_child("BottomCrop")->add_child_text (boost::lexical_cast (_crop.bottom)); -// for (vector >::const_iterator i = _subtitle_streams.begin(); i != _subtitle_streams.end(); ++i) { -// f << "subtitle_stream " << (*i)->to_string () << endl; -// } - -// f << "source_frame_rate " << _source_frame_rate << endl; + for (vector::const_iterator i = _filters.begin(); i != _filters.end(); ++i) { + root->add_child("Filter")->add_child_text ((*i)->id ()); + } + + root->add_child("Scaler")->add_child_text (_scaler->id ()); + root->add_child("TrimStart")->add_child_text (boost::lexical_cast (_trim_start)); + root->add_child("TrimEnd")->add_child_text (boost::lexical_cast (_trim_end)); + root->add_child("AB")->add_child_text (_ab ? "1" : "0"); + root->add_child("AudioGain")->add_child_text (boost::lexical_cast (_audio_gain)); + root->add_child("AudioDelay")->add_child_text (boost::lexical_cast (_audio_delay)); + root->add_child("WithSubtitles")->add_child_text (_with_subtitles ? "1" : "0"); + root->add_child("SubtitleOffset")->add_child_text (boost::lexical_cast (_subtitle_offset)); + root->add_child("SubtitleScale")->add_child_text (boost::lexical_cast (_subtitle_scale)); + root->add_child("ColourLUT")->add_child_text (boost::lexical_cast (_colour_lut)); + root->add_child("J2KBandwidth")->add_child_text (boost::lexical_cast (_j2k_bandwidth)); + _dci_metadata.as_xml (root->add_child ("DCIMetadata")); + root->add_child("DCIDate")->add_child_text (boost::gregorian::to_iso_string (_dci_date)); + root->add_child("DCPFrameRate")->add_child_text (boost::lexical_cast (_dcp_frame_rate)); + + for (ContentList::iterator i = the_content.begin(); i != the_content.end(); ++i) { + (*i)->as_xml (root->add_child ("Content")); + } + + doc.write_to_file_formatted (file ("metadata.xml")); _dirty = false; } @@ -456,137 +438,68 @@ Film::read_metadata () { boost::mutex::scoped_lock lm (_state_mutex); -// _external_audio.clear (); -// _content_audio_streams.clear (); -// _subtitle_streams.clear (); - - boost::optional version; - - /* Backward compatibility things */ - boost::optional audio_sample_rate; - boost::optional audio_stream_index; - boost::optional subtitle_stream_index; - - ifstream f (file ("metadata").c_str()); - if (!f.good()) { - throw OpenFileError (file ("metadata")); + if (boost::filesystem::exists (file ("metadata")) && !boost::filesystem::exists (file ("metadata.xml"))) { + throw StringError (_("This film was created with an older version of DVD-o-matic, and unfortunately it cannot be loaded into this version. You will need to create a new Film, re-add your content and set it up again. Sorry!")); } + + cxml::File f (file ("metadata.xml"), "Metadata"); - multimap kv = read_key_value (f); + _name = f.string_child ("Name"); + _use_dci_name = f.bool_child ("UseDCIName"); + _trust_content_headers = f.bool_child ("TrustContentHeaders"); - /* We need version before anything else */ - multimap::iterator v = kv.find ("version"); - if (v != kv.end ()) { - version = atoi (v->second.c_str()); + { + optional c = f.optional_string_child ("DCPContentType"); + if (c) { + _dcp_content_type = DCPContentType::from_dci_name (c.get ()); + } } - - for (multimap::const_iterator i = kv.begin(); i != kv.end(); ++i) { - string const k = i->first; - string const v = i->second; - if (k == "audio_sample_rate") { - audio_sample_rate = atoi (v.c_str()); + { + optional c = f.optional_string_child ("Format"); + if (c) { + _format = Format::from_id (c.get ()); } + } - /* User-specified stuff */ - if (k == "name") { - _name = v; - } else if (k == "use_dci_name") { - _use_dci_name = (v == "1"); - } else if (k == "content") { -// _content = v; - } else if (k == "trust_content_headers") { - _trust_content_headers = (v == "1"); - } else if (k == "dcp_content_type") { - if (version < 3) { - _dcp_content_type = DCPContentType::from_pretty_name (v); - } else { - _dcp_content_type = DCPContentType::from_dci_name (v); - } - } else if (k == "format") { - _format = Format::from_metadata (v); - } else if (k == "left_crop") { - _crop.left = atoi (v.c_str ()); - } else if (k == "right_crop") { - _crop.right = atoi (v.c_str ()); - } else if (k == "top_crop") { - _crop.top = atoi (v.c_str ()); - } else if (k == "bottom_crop") { - _crop.bottom = atoi (v.c_str ()); - } else if (k == "filter") { - _filters.push_back (Filter::from_id (v)); - } else if (k == "scaler") { - _scaler = Scaler::from_id (v); - } else if ( ((!version || version < 2) && k == "dcp_trim_start") || k == "trim_start") { - _trim_start = atoi (v.c_str ()); - } else if ( ((!version || version < 2) && k == "dcp_trim_end") || k == "trim_end") { - _trim_end = atoi (v.c_str ()); - } else if (k == "dcp_ab") { - _dcp_ab = (v == "1"); - } else if (k == "selected_content_audio_stream" || (!version && k == "selected_audio_stream")) { - if (!version) { - audio_stream_index = atoi (v.c_str ()); - } else { -// _content_audio_stream = audio_stream_factory (v, version); - } - } else if (k == "external_audio") { -// _external_audio.push_back (v); - } else if (k == "use_content_audio") { -// _use_content_audio = (v == "1"); - } else if (k == "audio_gain") { - _audio_gain = atof (v.c_str ()); - } else if (k == "audio_delay") { - _audio_delay = atoi (v.c_str ()); - } else if (k == "still_duration") { -// _still_duration = atoi (v.c_str ()); - } else if (k == "selected_subtitle_stream") { - if (!version) { - subtitle_stream_index = atoi (v.c_str ()); - } else { -// _subtitle_stream = subtitle_stream_factory (v, version); - } - } else if (k == "with_subtitles") { - _with_subtitles = (v == "1"); - } else if (k == "subtitle_offset") { - _subtitle_offset = atoi (v.c_str ()); - } else if (k == "subtitle_scale") { - _subtitle_scale = atof (v.c_str ()); - } else if (k == "colour_lut") { - _colour_lut = atoi (v.c_str ()); - } else if (k == "j2k_bandwidth") { - _j2k_bandwidth = atoi (v.c_str ()); - } else if (k == "dci_date") { - _dci_date = boost::gregorian::from_undelimited_string (v); - } else if (k == "dcp_frame_rate") { - _dcp_frame_rate = atoi (v.c_str ()); + _crop.left = f.number_child ("CropLeft"); + _crop.right = f.number_child ("CropRight"); + _crop.top = f.number_child ("CropTop"); + _crop.bottom = f.number_child ("CropBottom"); + + { + list > c = f.node_children ("Filter"); + for (list >::iterator i = c.begin(); i != c.end(); ++i) { + _filters.push_back (Filter::from_id ((*i)->content ())); } + } - _dci_metadata.read (k, v); + _scaler = Scaler::from_id (f.string_child ("Scaler")); + _trim_start = f.number_child ("TrimStart"); + _trim_end = f.number_child ("TrimEnd"); + _ab = f.bool_child ("AB"); + _audio_gain = f.number_child ("AudioGain"); + _audio_delay = f.number_child ("AudioDelay"); + _with_subtitles = f.bool_child ("WithSubtitles"); + _subtitle_offset = f.number_child ("SubtitleOffset"); + _subtitle_scale = f.number_child ("SubtitleScale"); + _colour_lut = f.number_child ("ColourLUT"); + _j2k_bandwidth = f.number_child ("J2KBandwidth"); + _dci_metadata = DCIMetadata (f.node_child ("DCIMetadata")); + _dci_date = boost::gregorian::from_undelimited_string (f.string_child ("DCIDate")); + _dcp_frame_rate = f.number_child ("DCPFrameRate"); + + list > c = f.node_children ("Content"); + for (list >::iterator i = c.begin(); i != c.end(); ++i) { + + string const type = (*i)->string_child ("Type"); - /* Cached stuff */ - if (k == "width") { -// _size.width = atoi (v.c_str ()); - } else if (k == "height") { -// _size.height = atoi (v.c_str ()); - } else if (k == "length") { - int const vv = atoi (v.c_str ()); - if (vv) { -// _length = vv; - } - } else if (k == "content_digest") { -// _content_digest = v; - } else if (k == "content_audio_stream" || (!version && k == "audio_stream")) { -// _content_audio_streams.push_back (audio_stream_factory (v, version)); - } else if (k == "external_audio_stream") { -// _sndfile_stream = audio_stream_factory (v, version); - } else if (k == "subtitle_stream") { -// _subtitle_streams.push_back (subtitle_stream_factory (v, version)); - } else if (k == "source_frame_rate") { -// _source_frame_rate = atof (v.c_str ()); - } else if (version < 4 && k == "frames_per_second") { -// _source_frame_rate = atof (v.c_str ()); - /* Fill in what would have been used for DCP frame rate by the older version */ -// _dcp_frame_rate = best_dcp_frame_rate (_source_frame_rate); + if (type == "FFmpeg") { + _content.push_back (shared_ptr (new FFmpegContent (*i))); + } else if (type == "ImageMagick") { + _content.push_back (shared_ptr (new ImageMagickContent (*i))); + } else if (type == "Sndfile") { + _content.push_back (shared_ptr (new SndfileContent (*i))); } } @@ -936,13 +849,13 @@ Film::set_trim_end (int t) } void -Film::set_dcp_ab (bool a) +Film::set_ab (bool a) { { boost::mutex::scoped_lock lm (_state_mutex); - _dcp_ab = a; + _ab = a; } - signal_changed (DCP_AB); + signal_changed (AB); } void diff --git a/src/lib/film.h b/src/lib/film.h index 928866161..f5f944409 100644 --- a/src/lib/film.h +++ b/src/lib/film.h @@ -123,7 +123,7 @@ public: SCALER, TRIM_START, TRIM_END, - DCP_AB, + AB, AUDIO_GAIN, AUDIO_DELAY, STILL_DURATION, @@ -200,9 +200,9 @@ public: return _trim_end; } - bool dcp_ab () const { + bool ab () const { boost::mutex::scoped_lock lm (_state_mutex); - return _dcp_ab; + return _ab; } float audio_gain () const { @@ -268,7 +268,7 @@ public: void set_scaler (Scaler const *); void set_trim_start (int); void set_trim_end (int); - void set_dcp_ab (bool); + void set_ab (bool); void set_audio_gain (float); void set_audio_delay (int); void set_still_duration (int); @@ -333,7 +333,7 @@ private: is the video without any filters or post-processing, and the right half has the specified filters and post-processing. */ - bool _dcp_ab; + bool _ab; /** Gain to apply to audio in dB */ float _audio_gain; /** Delay to apply to audio (positive moves audio later) in milliseconds */ diff --git a/src/lib/imagemagick_content.cc b/src/lib/imagemagick_content.cc index d096bff84..cb712b417 100644 --- a/src/lib/imagemagick_content.cc +++ b/src/lib/imagemagick_content.cc @@ -1,9 +1,11 @@ +#include #include "imagemagick_content.h" #include "compose.hpp" #include "i18n.h" using std::string; +using boost::shared_ptr; ImageMagickContent::ImageMagickContent (boost::filesystem::path f) : Content (f) @@ -13,6 +15,13 @@ ImageMagickContent::ImageMagickContent (boost::filesystem::path f) _video_length = 10 * 24; } +ImageMagickContent::ImageMagickContent (shared_ptr node) + : Content (node) + , VideoContent (node) +{ + +} + string ImageMagickContent::summary () const { diff --git a/src/lib/imagemagick_content.h b/src/lib/imagemagick_content.h index 0dd5baba8..99b614512 100644 --- a/src/lib/imagemagick_content.h +++ b/src/lib/imagemagick_content.h @@ -1,9 +1,14 @@ #include "video_content.h" +namespace cxml { + class Node; +} + class ImageMagickContent : public VideoContent { public: ImageMagickContent (boost::filesystem::path); + ImageMagickContent (boost::shared_ptr); std::string summary () const; diff --git a/src/lib/server.cc b/src/lib/server.cc index 9c5a77f68..ca0bec580 100644 --- a/src/lib/server.cc +++ b/src/lib/server.cc @@ -29,6 +29,7 @@ #include #include #include +#include #include "server.h" #include "util.h" #include "scaler.h" @@ -51,6 +52,19 @@ using boost::bind; using boost::scoped_array; using libdcp::Size; +ServerDescription::ServerDescription (shared_ptr node) +{ + _host_name = node->string_child ("HostName"); + _threads = node->number_child ("Threads"); +} + +void +ServerDescription::as_xml (xmlpp::Node* root) const +{ + root->add_child("HostName")->add_child_text (_host_name); + root->add_child("Threads")->add_child_text (boost::lexical_cast (_threads)); +} + /** Create a server description from a string of metadata returned from as_metadata(). * @param v Metadata. * @return ServerDescription, or 0. @@ -68,15 +82,6 @@ ServerDescription::create_from_metadata (string v) return new ServerDescription (b[0], atoi (b[1].c_str ())); } -/** @return Description of this server as text */ -string -ServerDescription::as_metadata () const -{ - stringstream s; - s << _host_name << N_(" ") << _threads; - return s.str (); -} - Server::Server (shared_ptr log) : _log (log) { diff --git a/src/lib/server.h b/src/lib/server.h index 89aeca626..398401a55 100644 --- a/src/lib/server.h +++ b/src/lib/server.h @@ -26,10 +26,15 @@ #include #include #include +#include #include "log.h" class Socket; +namespace cxml { + class Node; +} + /** @class ServerDescription * @brief Class to describe a server to which we can send encoding work. */ @@ -44,6 +49,8 @@ public: , _threads (t) {} + ServerDescription (boost::shared_ptr); + /** @return server's host name or IP address in string form */ std::string host_name () const { return _host_name; @@ -62,7 +69,7 @@ public: _threads = t; } - std::string as_metadata () const; + void as_xml (xmlpp::Node *) const; static ServerDescription * create_from_metadata (std::string v); diff --git a/src/lib/sndfile_content.cc b/src/lib/sndfile_content.cc index 53df4deea..4794e4d31 100644 --- a/src/lib/sndfile_content.cc +++ b/src/lib/sndfile_content.cc @@ -3,7 +3,8 @@ #include "i18n.h" -using namespace std; +using std::string; +using boost::shared_ptr; SndfileContent::SndfileContent (boost::filesystem::path f) : Content (f) @@ -12,6 +13,14 @@ SndfileContent::SndfileContent (boost::filesystem::path f) } +SndfileContent::SndfileContent (shared_ptr node) + : Content (node) + , AudioContent (node) + +{ + +} + string SndfileContent::summary () const { diff --git a/src/lib/sndfile_content.h b/src/lib/sndfile_content.h index 10cb428a1..b9a500c88 100644 --- a/src/lib/sndfile_content.h +++ b/src/lib/sndfile_content.h @@ -1,9 +1,14 @@ #include "audio_content.h" +namespace cxml { + class Node; +} + class SndfileContent : public AudioContent { public: SndfileContent (boost::filesystem::path); + SndfileContent (boost::shared_ptr); std::string summary () const; diff --git a/src/lib/transcoder.cc b/src/lib/transcoder.cc index 070258008..21944c5fc 100644 --- a/src/lib/transcoder.cc +++ b/src/lib/transcoder.cc @@ -28,7 +28,6 @@ #include #include "transcoder.h" #include "encoder.h" -#include "decoder_factory.h" #include "film.h" #include "matcher.h" #include "delay_line.h" diff --git a/src/lib/transcoder.h b/src/lib/transcoder.h index 3c47b0c7e..856b10f3a 100644 --- a/src/lib/transcoder.h +++ b/src/lib/transcoder.h @@ -23,8 +23,6 @@ * as a parameter to the constructor. */ -#include "decoder_factory.h" - class Film; class Job; class Encoder; diff --git a/src/lib/video_content.cc b/src/lib/video_content.cc index 9fc5cf1a2..8a4414c18 100644 --- a/src/lib/video_content.cc +++ b/src/lib/video_content.cc @@ -1,3 +1,4 @@ +#include #include "video_content.h" #include "video_decoder.h" @@ -5,7 +6,9 @@ int const VideoContentProperty::VIDEO_LENGTH = 0; int const VideoContentProperty::VIDEO_SIZE = 1; int const VideoContentProperty::VIDEO_FRAME_RATE = 2; +using std::string; using boost::shared_ptr; +using boost::lexical_cast; VideoContent::VideoContent (boost::filesystem::path f) : Content (f) @@ -14,6 +17,25 @@ VideoContent::VideoContent (boost::filesystem::path f) } +VideoContent::VideoContent (shared_ptr node) + : Content (node) +{ + _video_length = node->number_child ("VideoLength"); + _video_size.width = node->number_child ("VideoWidth"); + _video_size.height = node->number_child ("VideoHeight"); + _video_frame_rate = node->number_child ("VideoFrameRate"); +} + +void +VideoContent::as_xml (xmlpp::Node* node) const +{ + boost::mutex::scoped_lock lm (_mutex); + node->add_child("VideoLength")->add_child_text (lexical_cast (_video_length)); + node->add_child("VideoWidth")->add_child_text (lexical_cast (_video_size.width)); + node->add_child("VideoHeight")->add_child_text (lexical_cast (_video_size.height)); + node->add_child("VideoFrameRate")->add_child_text (lexical_cast (_video_frame_rate)); +} + void VideoContent::take_from_video_decoder (shared_ptr d) { diff --git a/src/lib/video_content.h b/src/lib/video_content.h index 219130668..7c9db890a 100644 --- a/src/lib/video_content.h +++ b/src/lib/video_content.h @@ -18,6 +18,9 @@ class VideoContent : public virtual Content { public: VideoContent (boost::filesystem::path); + VideoContent (boost::shared_ptr); + + void as_xml (xmlpp::Node *) const; ContentVideoFrame video_length () const { boost::mutex::scoped_lock lm (_mutex); diff --git a/src/lib/wscript b/src/lib/wscript index 5510d48a8..303a9951f 100644 --- a/src/lib/wscript +++ b/src/lib/wscript @@ -17,7 +17,6 @@ sources = """ dcp_content_type.cc dcp_video_frame.cc decoder.cc - decoder_factory.cc delay_line.cc dolby_cp750.cc encoder.cc @@ -70,7 +69,7 @@ def build(bld): obj.uselib = """ AVCODEC AVUTIL AVFORMAT AVFILTER SWSCALE SWRESAMPLE BOOST_FILESYSTEM BOOST_THREAD BOOST_DATETIME BOOST_SIGNALS2 - SNDFILE OPENJPEG POSTPROC TIFF MAGICK SSH DCP GLIB LZMA + SNDFILE OPENJPEG POSTPROC TIFF MAGICK SSH DCP CXML GLIB LZMA """ if bld.env.TARGET_WINDOWS: obj.uselib += ' WINSOCK2' diff --git a/src/tools/makedcp.cc b/src/tools/makedcp.cc index 226cde113..85134b3c5 100644 --- a/src/tools/makedcp.cc +++ b/src/tools/makedcp.cc @@ -146,7 +146,7 @@ main (int argc, char* argv[]) film->log()->set_level ((Log::Level) log_level); cout << "\nMaking "; - if (film->dcp_ab()) { + if (film->ab()) { cout << "A/B "; } cout << "DCP for " << film->name() << "\n"; diff --git a/src/tools/servomatictest.cc b/src/tools/servomatictest.cc index d08fefa90..3d847d690 100644 --- a/src/tools/servomatictest.cc +++ b/src/tools/servomatictest.cc @@ -32,8 +32,8 @@ #include "exceptions.h" #include "scaler.h" #include "log.h" -#include "decoder_factory.h" #include "video_decoder.h" +#include "playlist.h" using std::cout; using std::cerr; @@ -150,17 +150,14 @@ main (int argc, char* argv[]) server = new ServerDescription (server_host, 1); shared_ptr film (new Film (film_dir, true)); - /* XXX */ -// opt.decode_audio = false; -// opt.decode_subtitles = true; -// opt.video_sync = true; + shared_ptr playlist = film->playlist (); + playlist->disable_audio (); - Decoders decoders = decoder_factory (film); try { - decoders.video->Video.connect (boost::bind (process_video, _1, _2, _3)); + playlist->Video.connect (boost::bind (process_video, _1, _2, _3)); bool done = false; while (!done) { - done = decoders.video->pass (); + done = playlist->pass (); } } catch (std::exception& e) { cerr << "Error: " << e.what() << "\n"; diff --git a/src/wx/audio_plot.cc b/src/wx/audio_plot.cc index cf44eb69f..2a6210164 100644 --- a/src/wx/audio_plot.cc +++ b/src/wx/audio_plot.cc @@ -21,7 +21,6 @@ #include #include #include "audio_plot.h" -#include "lib/decoder_factory.h" #include "lib/audio_decoder.h" #include "lib/audio_analysis.h" #include "wx/wx_util.h" diff --git a/src/wx/film_editor.cc b/src/wx/film_editor.cc index 40f4f0362..560c4ef27 100644 --- a/src/wx/film_editor.cc +++ b/src/wx/film_editor.cc @@ -175,8 +175,8 @@ FilmEditor::make_film_panel () } ++r; - _dcp_ab = new wxCheckBox (_film_panel, wxID_ANY, _("A/B")); - grid->Add (_dcp_ab, wxGBPosition (r, 0)); + _ab = new wxCheckBox (_film_panel, wxID_ANY, _("A/B")); + grid->Add (_ab, wxGBPosition (r, 0)); ++r; vector const ct = DCPContentType::all (); @@ -212,7 +212,7 @@ FilmEditor::connect_to_widgets () _dcp_content_type->Connect (wxID_ANY, wxEVT_COMMAND_CHOICE_SELECTED, wxCommandEventHandler (FilmEditor::dcp_content_type_changed), 0, this); _dcp_frame_rate->Connect (wxID_ANY, wxEVT_COMMAND_CHOICE_SELECTED, wxCommandEventHandler (FilmEditor::dcp_frame_rate_changed), 0, this); _best_dcp_frame_rate->Connect (wxID_ANY, wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler (FilmEditor::best_dcp_frame_rate_clicked), 0, this); - _dcp_ab->Connect (wxID_ANY, wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler (FilmEditor::dcp_ab_toggled), 0, this); + _ab->Connect (wxID_ANY, wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler (FilmEditor::ab_toggled), 0, this); _trim_start->Connect (wxID_ANY, wxEVT_COMMAND_SPINCTRL_UPDATED, wxCommandEventHandler (FilmEditor::trim_start_changed), 0, this); _trim_end->Connect (wxID_ANY, wxEVT_COMMAND_SPINCTRL_UPDATED, wxCommandEventHandler (FilmEditor::trim_end_changed), 0, this); _with_subtitles->Connect (wxID_ANY, wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler (FilmEditor::with_subtitles_toggled), 0, this); @@ -489,13 +489,13 @@ FilmEditor::trust_content_headers_changed (wxCommandEvent &) /** Called when the DCP A/B switch has been toggled */ void -FilmEditor::dcp_ab_toggled (wxCommandEvent &) +FilmEditor::ab_toggled (wxCommandEvent &) { if (!_film) { return; } - _film->set_dcp_ab (_dcp_ab->GetValue ()); + _film->set_ab (_ab->GetValue ()); } /** Called when the name widget has been changed */ @@ -674,8 +674,8 @@ FilmEditor::film_changed (Film::Property p) checked_set (_dcp_content_type, DCPContentType::as_index (_film->dcp_content_type ())); setup_dcp_name (); break; - case Film::DCP_AB: - checked_set (_dcp_ab, _film->dcp_ab ()); + case Film::AB: + checked_set (_ab, _film->ab ()); break; case Film::SCALER: checked_set (_scaler, Scaler::as_index (_film->scaler ())); @@ -811,7 +811,7 @@ FilmEditor::set_film (shared_ptr f) film_changed (Film::SCALER); film_changed (Film::TRIM_START); film_changed (Film::TRIM_END); - film_changed (Film::DCP_AB); + film_changed (Film::AB); film_changed (Film::AUDIO_GAIN); film_changed (Film::AUDIO_DELAY); film_changed (Film::WITH_SUBTITLES); @@ -849,7 +849,7 @@ FilmEditor::set_things_sensitive (bool s) _dcp_frame_rate->Enable (s); _trim_start->Enable (s); _trim_end->Enable (s); - _dcp_ab->Enable (s); + _ab->Enable (s); _colour_lut->Enable (s); _j2k_bandwidth->Enable (s); _audio_gain->Enable (s); diff --git a/src/wx/film_editor.h b/src/wx/film_editor.h index 50457bdce..80072d48a 100644 --- a/src/wx/film_editor.h +++ b/src/wx/film_editor.h @@ -72,7 +72,7 @@ private: void trim_start_changed (wxCommandEvent &); void trim_end_changed (wxCommandEvent &); void dcp_content_type_changed (wxCommandEvent &); - void dcp_ab_toggled (wxCommandEvent &); + void ab_toggled (wxCommandEvent &); void scaler_changed (wxCommandEvent &); void audio_gain_changed (wxCommandEvent &); void audio_gain_calculate_button_clicked (wxCommandEvent &); @@ -162,7 +162,7 @@ private: wxSpinCtrl* _trim_start; wxSpinCtrl* _trim_end; /** Selector to generate an A/B comparison DCP */ - wxCheckBox* _dcp_ab; + wxCheckBox* _ab; std::vector _formats; diff --git a/src/wx/film_viewer.h b/src/wx/film_viewer.h index b552a3dbc..74ab9798c 100644 --- a/src/wx/film_viewer.h +++ b/src/wx/film_viewer.h @@ -23,7 +23,6 @@ #include #include "lib/film.h" -#include "lib/decoder_factory.h" class wxToggleButton; class FFmpegPlayer; diff --git a/test/test.cc b/test/test.cc index efa4848f6..5cf3dc56d 100644 --- a/test/test.cc +++ b/test/test.cc @@ -155,7 +155,7 @@ BOOST_AUTO_TEST_CASE (film_metadata_test) f->set_filters (f_filters); f->set_trim_start (42); f->set_trim_end (99); - f->set_dcp_ab (true); + f->set_ab (true); f->write_metadata (); stringstream s; @@ -177,7 +177,7 @@ BOOST_AUTO_TEST_CASE (film_metadata_test) BOOST_CHECK_EQUAL (g_filters.back(), Filter::from_id ("unsharp")); BOOST_CHECK_EQUAL (g->trim_start(), 42); BOOST_CHECK_EQUAL (g->trim_end(), 99); - BOOST_CHECK_EQUAL (g->dcp_ab(), true); + BOOST_CHECK_EQUAL (g->ab(), true); g->write_metadata (); BOOST_CHECK_EQUAL (::system (s.str().c_str ()), 0); -- cgit v1.2.3 From f385ef03e5ea27519a31c0839447735a7fba0602 Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Fri, 31 May 2013 14:19:50 +0100 Subject: Various stuff; mostly change to decoder scaling and adding subtitle; scaling test. --- src/lib/ab_transcode_job.cc | 3 -- src/lib/ab_transcoder.cc | 4 +- src/lib/combiner.cc | 6 +-- src/lib/combiner.h | 4 +- src/lib/config.cc | 6 +-- src/lib/config.h | 10 ++-- src/lib/container.cc | 78 --------------------------- src/lib/container.h | 70 ------------------------ src/lib/dcp_video_frame.cc | 105 +++++++++++------------------------- src/lib/dcp_video_frame.h | 18 ++----- src/lib/encoder.cc | 18 ++----- src/lib/encoder.h | 6 +-- src/lib/ffmpeg_decoder.cc | 3 -- src/lib/ffmpeg_decoder.h | 4 +- src/lib/film.cc | 6 +-- src/lib/film.h | 7 ++- src/lib/format.cc | 126 -------------------------------------------- src/lib/format.h | 80 ---------------------------- src/lib/image.cc | 46 +++++++--------- src/lib/image.h | 3 +- src/lib/player.cc | 23 ++++++-- src/lib/player.h | 3 +- src/lib/ratio.cc | 71 +++++++++++++++++++++++++ src/lib/ratio.h | 66 +++++++++++++++++++++++ src/lib/server.cc | 35 +++--------- src/lib/transcode_job.cc | 2 - src/lib/util.cc | 6 +-- src/lib/video_content.cc | 31 ++++++++++- src/lib/video_content.h | 10 ++++ src/lib/video_decoder.cc | 38 ++++++++++--- src/lib/video_sink.h | 3 +- src/lib/video_source.cc | 6 +-- src/lib/video_source.h | 5 +- src/lib/writer.cc | 3 +- src/lib/wscript | 3 +- src/tools/dcpomatic.cc | 4 -- src/tools/dcpomatic_cli.cc | 1 - src/wx/config_dialog.cc | 12 ++--- src/wx/film_editor.cc | 46 ++++++++-------- src/wx/film_editor.h | 10 ++-- src/wx/film_viewer.cc | 41 ++------------ src/wx/film_viewer.h | 12 ++--- test/client_server_test.cc | 6 --- test/container_test.cc | 73 ------------------------- test/dcp_test.cc | 2 +- test/film_metadata_test.cc | 4 +- test/format_test.cc | 33 ------------ test/make_black_test.cc | 2 +- test/ratio_test.cc | 73 +++++++++++++++++++++++++ test/scaling_test.cc | 43 ++++++++++++++- test/test.cc | 64 ++++++++++++++++++++-- 51 files changed, 549 insertions(+), 785 deletions(-) delete mode 100644 src/lib/container.cc delete mode 100644 src/lib/container.h delete mode 100644 src/lib/format.cc delete mode 100644 src/lib/format.h create mode 100644 src/lib/ratio.cc create mode 100644 src/lib/ratio.h delete mode 100644 test/container_test.cc delete mode 100644 test/format_test.cc create mode 100644 test/ratio_test.cc (limited to 'src/lib/server.cc') 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" -- cgit v1.2.3 From 320a74efb8d9c8aacded2799459a92d5b7235d90 Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Wed, 10 Jul 2013 20:29:00 +0100 Subject: Make subtitles work at least a bit. --- src/lib/decoder.h | 2 - src/lib/ffmpeg_decoder.cc | 64 ++++++++++++++++--- src/lib/image.cc | 4 +- src/lib/image.h | 5 +- src/lib/player.cc | 77 +++++++++++++++-------- src/lib/player.h | 23 +++++-- src/lib/position.h | 46 ++++++++++++++ src/lib/rect.h | 79 +++++++++++++++++++++++ src/lib/server.cc | 1 - src/lib/subtitle.cc | 149 -------------------------------------------- src/lib/subtitle.h | 82 ------------------------ src/lib/subtitle_content.cc | 4 +- src/lib/subtitle_content.h | 16 ++--- src/lib/subtitle_decoder.cc | 8 +-- src/lib/subtitle_decoder.h | 6 +- src/lib/types.cc | 22 ------- src/lib/types.h | 62 ------------------ src/lib/video_decoder.cc | 3 - src/lib/wscript | 1 - src/wx/film_editor.cc | 8 +-- src/wx/timeline.cc | 18 +++--- src/wx/timeline.h | 7 ++- test/client_server_test.cc | 2 +- test/test.cc | 1 - 24 files changed, 287 insertions(+), 403 deletions(-) create mode 100644 src/lib/position.h create mode 100644 src/lib/rect.h delete mode 100644 src/lib/subtitle.cc delete mode 100644 src/lib/subtitle.h (limited to 'src/lib/server.cc') diff --git a/src/lib/decoder.h b/src/lib/decoder.h index cfca6867f..dea4def3a 100644 --- a/src/lib/decoder.h +++ b/src/lib/decoder.h @@ -34,8 +34,6 @@ class Image; class Log; class DelayLine; -class TimedSubtitle; -class Subtitle; class FilterGraph; /** @class Decoder. diff --git a/src/lib/ffmpeg_decoder.cc b/src/lib/ffmpeg_decoder.cc index 3714c1542..fddb70294 100644 --- a/src/lib/ffmpeg_decoder.cc +++ b/src/lib/ffmpeg_decoder.cc @@ -41,7 +41,6 @@ extern "C" { #include "log.h" #include "ffmpeg_decoder.h" #include "filter_graph.h" -#include "subtitle.h" #include "audio_buffers.h" #include "i18n.h" @@ -478,20 +477,65 @@ FFmpegDecoder::decode_subtitle_packet () if (avcodec_decode_subtitle2 (_subtitle_codec_context, &sub, &got_subtitle, &_packet) < 0 || !got_subtitle) { return; } - + /* Sometimes we get an empty AVSubtitle, which is used by some codecs to indicate that the previous subtitle should stop. */ - if (sub.num_rects > 0) { - shared_ptr ts; - try { - subtitle (shared_ptr (new TimedSubtitle (sub))); - } catch (...) { - /* some problem with the subtitle; we probably didn't understand it */ + if (sub.num_rects <= 0) { + subtitle (shared_ptr (), dcpomatic::Rect (), 0, 0); + return; + } else if (sub.num_rects > 1) { + throw DecodeError (_("multi-part subtitles not yet supported")); + } + + /* Subtitle PTS in seconds (within the source, not taking into account any of the + source that we may have chopped off for the DCP) + */ + double const packet_time = static_cast (sub.pts) / AV_TIME_BASE; + + /* hence start time for this sub */ + Time const from = (packet_time + (double (sub.start_display_time) / 1e3)) * TIME_HZ; + Time const to = (packet_time + (double (sub.end_display_time) / 1e3)) * TIME_HZ; + + AVSubtitleRect const * rect = sub.rects[0]; + + if (rect->type != SUBTITLE_BITMAP) { + throw DecodeError (_("non-bitmap subtitles not yet supported")); + } + + shared_ptr image (new SimpleImage (PIX_FMT_RGBA, libdcp::Size (rect->w, rect->h), true)); + + /* Start of the first line in the subtitle */ + uint8_t* sub_p = rect->pict.data[0]; + /* sub_p looks up into a RGB palette which is here */ + uint32_t const * palette = (uint32_t *) rect->pict.data[1]; + /* Start of the output data */ + uint32_t* out_p = (uint32_t *) image->data()[0]; + + for (int y = 0; y < rect->h; ++y) { + uint8_t* sub_line_p = sub_p; + uint32_t* out_line_p = out_p; + for (int x = 0; x < rect->w; ++x) { + *out_line_p++ = palette[*sub_line_p++]; } - } else { - subtitle (shared_ptr ()); + sub_p += rect->pict.linesize[0]; + out_p += image->stride()[0] / sizeof (uint32_t); } + + libdcp::Size const vs = _ffmpeg_content->video_size (); + + subtitle ( + image, + dcpomatic::Rect ( + static_cast (rect->x) / vs.width, + static_cast (rect->y) / vs.height, + static_cast (rect->w) / vs.width, + static_cast (rect->h) / vs.height + ), + from, + to + ); + avsubtitle_free (&sub); } diff --git a/src/lib/image.cc b/src/lib/image.cc index ac30f4ff0..c11bcbb8d 100644 --- a/src/lib/image.cc +++ b/src/lib/image.cc @@ -336,7 +336,7 @@ Image::make_black () } void -Image::alpha_blend (shared_ptr other, Position position) +Image::alpha_blend (shared_ptr other, Position position) { /* Only implemented for RGBA onto RGB24 so far */ assert (_pixel_format == PIX_FMT_RGB24 && other->pixel_format() == PIX_FMT_RGBA); @@ -372,7 +372,7 @@ Image::alpha_blend (shared_ptr other, Position position) } void -Image::copy (shared_ptr other, Position position) +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); diff --git a/src/lib/image.h b/src/lib/image.h index 5407ce66e..d40ba77b4 100644 --- a/src/lib/image.h +++ b/src/lib/image.h @@ -32,6 +32,7 @@ extern "C" { #include } #include "util.h" +#include "position.h" class Scaler; class SimpleImage; @@ -75,8 +76,8 @@ public: 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); + 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 c615f0a89..58ba57bdc 100644 --- a/src/lib/player.cc +++ b/src/lib/player.cc @@ -32,7 +32,7 @@ #include "image.h" #include "ratio.h" #include "resampler.h" -#include "subtitle.h" +#include "scaler.h" using std::list; using std::cout; @@ -45,7 +45,7 @@ using boost::shared_ptr; using boost::weak_ptr; using boost::dynamic_pointer_cast; -#define DEBUG_PLAYER 1 +//#define DEBUG_PLAYER 1 class Piece { @@ -225,22 +225,8 @@ Player::process_video (weak_ptr weak_piece, shared_ptr image Time time = content->start() + (frame * frc.factor() * TIME_HZ / _film->dcp_video_frame_rate()); - if (_film->with_subtitles ()) { - shared_ptr sub; - if (_subtitle && _subtitle->displayed_at (time - _subtitle_content_time)) { - sub = _subtitle->subtitle (); - } - - if (sub) { - dcpomatic::Rect const tx = subtitle_transformed_area ( - float (image_size.width) / content->video_size().width, - float (image_size.height) / content->video_size().height, - sub->area(), _subtitle_offset, _subtitle_scale - ); - - shared_ptr im = sub->image()->scale (tx.size(), _film->scaler(), true); - work_image->alpha_blend (im, tx.position()); - } + if (_film->with_subtitles () && _out_subtitle.image && time >= _out_subtitle.from && time <= _out_subtitle.to) { + work_image->alpha_blend (_out_subtitle.image, _out_subtitle.position); } if (image_size != _video_container_size) { @@ -248,7 +234,7 @@ Player::process_video (weak_ptr weak_piece, shared_ptr image assert (image_size.height <= _video_container_size.height); shared_ptr im (new SimpleImage (PIX_FMT_RGB24, _video_container_size, true)); im->make_black (); - im->copy (work_image, Position ((_video_container_size.width - image_size.width) / 2, (_video_container_size.height - image_size.height) / 2)); + im->copy (work_image, Position ((_video_container_size.width - image_size.width) / 2, (_video_container_size.height - image_size.height) / 2)); work_image = im; } @@ -390,7 +376,7 @@ Player::setup_pieces () fd->Video.connect (bind (&Player::process_video, this, piece, _1, _2, _3)); fd->Audio.connect (bind (&Player::process_audio, this, piece, _1, _2)); - fd->Subtitle.connect (bind (&Player::process_subtitle, this, piece, _1)); + fd->Subtitle.connect (bind (&Player::process_subtitle, this, piece, _1, _2, _3, _4)); piece->decoder = fd; } @@ -449,6 +435,10 @@ Player::content_changed (weak_ptr w, int p) _have_valid_pieces = false; Changed (); + + } else if (p == SubtitleContentProperty::SUBTITLE_OFFSET || p == SubtitleContentProperty::SUBTITLE_SCALE) { + update_subtitle (); + Changed (); } } @@ -512,9 +502,21 @@ Player::film_changed (Film::Property p) } void -Player::process_subtitle (weak_ptr weak_piece, shared_ptr sub) +Player::process_subtitle (weak_ptr weak_piece, shared_ptr image, dcpomatic::Rect rect, Time from, Time to) { - shared_ptr piece = weak_piece.lock (); + _in_subtitle.piece = weak_piece; + _in_subtitle.image = image; + _in_subtitle.rect = rect; + _in_subtitle.from = from; + _in_subtitle.to = to; + + update_subtitle (); +} + +void +Player::update_subtitle () +{ + shared_ptr piece = _in_subtitle.piece.lock (); if (!piece) { return; } @@ -522,8 +524,31 @@ Player::process_subtitle (weak_ptr weak_piece, shared_ptr shared_ptr sc = dynamic_pointer_cast (piece->content); assert (sc); - _subtitle = sub; - _subtitle_content_time = piece->content->start (); - _subtitle_offset = sc->subtitle_offset (); - _subtitle_scale = sc->subtitle_scale (); + dcpomatic::Rect in_rect = _in_subtitle.rect; + libdcp::Size scaled_size; + + in_rect.y += sc->subtitle_offset (); + + /* We will scale the subtitle up to fit _video_container_size, and also by the additional subtitle_scale */ + scaled_size.width = in_rect.width * _video_container_size.width * sc->subtitle_scale (); + scaled_size.height = in_rect.height * _video_container_size.height * sc->subtitle_scale (); + + /* Then we need a corrective translation, consisting of two parts: + * + * 1. that which is the result of the scaling of the subtitle by _video_container_size; this will be + * rect.x * _video_container_size.width and rect.y * _video_container_size.height. + * + * 2. that to shift the origin of the scale by subtitle_scale to the centre of the subtitle; this will be + * (width_before_subtitle_scale * (1 - subtitle_scale) / 2) and + * (height_before_subtitle_scale * (1 - subtitle_scale) / 2). + * + * Combining these two translations gives these expressions. + */ + + _out_subtitle.position.x = rint (_video_container_size.width * (in_rect.x + (in_rect.width * (1 - sc->subtitle_scale ()) / 2))); + _out_subtitle.position.y = rint (_video_container_size.height * (in_rect.y + (in_rect.height * (1 - sc->subtitle_scale ()) / 2))); + + _out_subtitle.image = _in_subtitle.image->scale (libdcp::Size (scaled_size.width, scaled_size.height), Scaler::from_id ("bicubic"), true); + _out_subtitle.from = _in_subtitle.from + piece->content->start (); + _out_subtitle.to = _in_subtitle.to + piece->content->start (); } diff --git a/src/lib/player.h b/src/lib/player.h index 32ef25d47..5a4ee97be 100644 --- a/src/lib/player.h +++ b/src/lib/player.h @@ -27,6 +27,7 @@ #include "audio_buffers.h" #include "content.h" #include "film.h" +#include "rect.h" class Job; class Film; @@ -35,7 +36,6 @@ class AudioContent; class Piece; class Image; class Resampler; -class TimedSubtitle; /** @class Player * @brief A class which can `play' a Playlist; emitting its audio and video. @@ -78,7 +78,7 @@ private: void process_video (boost::weak_ptr, boost::shared_ptr, bool, VideoContent::Frame); void process_audio (boost::weak_ptr, boost::shared_ptr, AudioContent::Frame); - void process_subtitle (boost::weak_ptr, boost::shared_ptr); + void process_subtitle (boost::weak_ptr, boost::shared_ptr, dcpomatic::Rect, Time, Time); void setup_pieces (); void playlist_changed (); void content_changed (boost::weak_ptr, int); @@ -88,6 +88,7 @@ private: void emit_silence (OutputAudioFrame); boost::shared_ptr resampler (boost::shared_ptr); void film_changed (Film::Property); + void update_subtitle (); boost::shared_ptr _film; boost::shared_ptr _playlist; @@ -110,10 +111,20 @@ private: boost::shared_ptr _black_frame; std::map, boost::shared_ptr > _resamplers; - boost::shared_ptr _subtitle; - Time _subtitle_content_time; - int _subtitle_offset; - float _subtitle_scale; + struct { + boost::weak_ptr piece; + boost::shared_ptr image; + dcpomatic::Rect rect; + Time from; + Time to; + } _in_subtitle; + + struct { + boost::shared_ptr image; + Position position; + Time from; + Time to; + } _out_subtitle; }; #endif diff --git a/src/lib/position.h b/src/lib/position.h new file mode 100644 index 000000000..f904fe661 --- /dev/null +++ b/src/lib/position.h @@ -0,0 +1,46 @@ +/* + 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. + +*/ + +#ifndef DVDOMATIC_POSITION_H +#define DVDOMATIC_POSITION_H + +/** @struct Position + * @brief A position. + */ +template +class Position +{ +public: + Position () + : x (0) + , y (0) + {} + + Position (T x_, T y_) + : x (x_) + , y (y_) + {} + + /** x coordinate */ + T x; + /** y coordinate */ + T y; +}; + +#endif diff --git a/src/lib/rect.h b/src/lib/rect.h new file mode 100644 index 000000000..df1869841 --- /dev/null +++ b/src/lib/rect.h @@ -0,0 +1,79 @@ +/* + 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. + +*/ + +#ifndef DVDOMATIC_RECT_H +#define DVDOMATIC_RECT_H + +#include "position.h" + +/* Put this inside a namespace as Apple put a Rect in the global namespace */ + +namespace dcpomatic +{ + +/** @struct Rect + * @brief A rectangle. + */ +template +class Rect +{ +public: + + Rect () + : x (0) + , y (0) + , width (0) + , height (0) + {} + + Rect (T x_, T y_, T w_, T h_) + : x (x_) + , y (y_) + , width (w_) + , height (h_) + {} + + T x; + T y; + T width; + T height; + + Position position () const { + return Position (x, y); + } + + Rect intersection (Rect const & other) const { + T const tx = max (x, other.x); + T const ty = max (y, other.y); + + return Rect ( + tx, ty, + min (x + width, other.x + other.width) - tx, + min (y + height, other.y + other.height) - ty + ); + } + + bool contains (Position p) const { + return (p.x >= x && p.x <= (x + width) && p.y >= y && p.y <= (y + height)); + } +}; + +} + +#endif diff --git a/src/lib/server.cc b/src/lib/server.cc index 5ca04c692..40d1c4c0c 100644 --- a/src/lib/server.cc +++ b/src/lib/server.cc @@ -36,7 +36,6 @@ #include "image.h" #include "dcp_video_frame.h" #include "config.h" -#include "subtitle.h" #include "i18n.h" diff --git a/src/lib/subtitle.cc b/src/lib/subtitle.cc deleted file mode 100644 index 7013f1d7d..000000000 --- a/src/lib/subtitle.cc +++ /dev/null @@ -1,149 +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/subtitle.cc - * @brief Representations of subtitles. - */ - -#include "subtitle.h" -#include "image.h" -#include "exceptions.h" - -#include "i18n.h" - -using boost::shared_ptr; -using libdcp::Size; - -/** Construct a TimedSubtitle. This is a subtitle image, position, - * and a range of time over which it should be shown. - * @param sub AVSubtitle to read. - */ -TimedSubtitle::TimedSubtitle (AVSubtitle const & sub) -{ - assert (sub.num_rects > 0); - - /* Subtitle PTS in seconds (within the source, not taking into account any of the - source that we may have chopped off for the DCP) - */ - double const packet_time = static_cast (sub.pts) / AV_TIME_BASE; - - /* hence start time for this sub */ - _from = (packet_time + (double (sub.start_display_time) / 1e3)) * TIME_HZ; - _to = (packet_time + (double (sub.end_display_time) / 1e3)) * TIME_HZ; - - if (sub.num_rects > 1) { - throw DecodeError (_("multi-part subtitles not yet supported")); - } - - AVSubtitleRect const * rect = sub.rects[0]; - - if (rect->type != SUBTITLE_BITMAP) { - throw DecodeError (_("non-bitmap subtitles not yet supported")); - } - - shared_ptr image (new SimpleImage (PIX_FMT_RGBA, libdcp::Size (rect->w, rect->h), true)); - - /* Start of the first line in the subtitle */ - uint8_t* sub_p = rect->pict.data[0]; - /* sub_p looks up into a RGB palette which is here */ - uint32_t const * palette = (uint32_t *) rect->pict.data[1]; - /* Start of the output data */ - uint32_t* out_p = (uint32_t *) image->data()[0]; - - for (int y = 0; y < rect->h; ++y) { - uint8_t* sub_line_p = sub_p; - uint32_t* out_line_p = out_p; - for (int x = 0; x < rect->w; ++x) { - *out_line_p++ = palette[*sub_line_p++]; - } - sub_p += rect->pict.linesize[0]; - out_p += image->stride()[0] / sizeof (uint32_t); - } - - _subtitle.reset (new Subtitle (Position (rect->x, rect->y), image)); -} - -/** @param t Time from the start of the source */ -bool -TimedSubtitle::displayed_at (Time t) const -{ - return t >= _from && t <= _to; -} - -/** Construct a subtitle, which is an image and a position. - * @param p Position within the (uncropped) source frame. - * @param i Image of the subtitle (should be RGBA). - */ -Subtitle::Subtitle (Position p, shared_ptr i) - : _position (p) - , _image (i) -{ - -} - -/** Given the area of a subtitle, work out the area it should - * take up when its video frame is scaled up, and it is optionally - * itself scaled and offset. - * @param target_x_scale the x scaling of the video frame that the subtitle is in. - * @param target_y_scale the y scaling of the video frame that the subtitle is in. - * @param sub_area The area of the subtitle within the original source. - * @param subtitle_offset y offset to apply to the subtitle position (+ve is down) - * in the coordinate space of the source. - * @param subtitle_scale scaling factor to apply to the subtitle image. - */ -dcpomatic::Rect -subtitle_transformed_area ( - float target_x_scale, float target_y_scale, - dcpomatic::Rect sub_area, int subtitle_offset, float subtitle_scale - ) -{ - dcpomatic::Rect tx; - - sub_area.y += subtitle_offset; - - /* We will scale the subtitle by the same amount as the video frame, and also by the additional - subtitle_scale - */ - tx.width = sub_area.width * target_x_scale * subtitle_scale; - tx.height = sub_area.height * target_y_scale * subtitle_scale; - - /* Then we need a corrective translation, consisting of two parts: - * - * 1. that which is the result of the scaling of the subtitle by target_x_scale and target_y_scale; this will be - * sub_area.x * target_x_scale and sub_area.y * target_y_scale. - * - * 2. that to shift the origin of the scale by subtitle_scale to the centre of the subtitle; this will be - * (width_before_subtitle_scale * (1 - subtitle_scale) / 2) and - * (height_before_subtitle_scale * (1 - subtitle_scale) / 2). - * - * Combining these two translations gives these expressions. - */ - - tx.x = rint (target_x_scale * (sub_area.x + (sub_area.width * (1 - subtitle_scale) / 2))); - tx.y = rint (target_y_scale * (sub_area.y + (sub_area.height * (1 - subtitle_scale) / 2))); - - return tx; -} - -/** @return area that this subtitle takes up, in the original uncropped source's coordinate space */ -dcpomatic::Rect -Subtitle::area () const -{ - return dcpomatic::Rect (_position.x, _position.y, _image->size().width, _image->size().height); -} diff --git a/src/lib/subtitle.h b/src/lib/subtitle.h deleted file mode 100644 index 47735c453..000000000 --- a/src/lib/subtitle.h +++ /dev/null @@ -1,82 +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/subtitle.h - * @brief Representations of subtitles. - */ - -#include -#include -#include "types.h" - -struct AVSubtitle; -class Image; - -/** A subtitle, consisting of an image and a position */ -class Subtitle -{ -public: - Subtitle (Position p, boost::shared_ptr i); - - void set_position (Position p) { - _position = p; - } - - Position position () const { - return _position; - } - - boost::shared_ptr image () const { - return _image; - } - - dcpomatic::Rect area () const; - -private: - Position _position; - boost::shared_ptr _image; -}; - -dcpomatic::Rect -subtitle_transformed_area ( - float target_x_scale, float target_y_scale, - dcpomatic::Rect sub_area, int subtitle_offset, float subtitle_scale - ); - -/** A Subtitle class with details of the time over which it should be shown */ -/** XXX: merge with Subtitle? */ -class TimedSubtitle -{ -public: - TimedSubtitle (AVSubtitle const &); - - bool displayed_at (Time) const; - - boost::shared_ptr subtitle () const { - return _subtitle; - } - -private: - /** the subtitle */ - boost::shared_ptr _subtitle; - /** display from time from the start of the content */ - Time _from; - /** display to time from the start of the content */ - Time _to; -}; diff --git a/src/lib/subtitle_content.cc b/src/lib/subtitle_content.cc index c8de9887e..9fefbbfcd 100644 --- a/src/lib/subtitle_content.cc +++ b/src/lib/subtitle_content.cc @@ -52,7 +52,7 @@ SubtitleContent::as_xml (xmlpp::Node* root) const } void -SubtitleContent::set_subtitle_offset (int o) +SubtitleContent::set_subtitle_offset (double o) { { boost::mutex::scoped_lock lm (_mutex); @@ -62,7 +62,7 @@ SubtitleContent::set_subtitle_offset (int o) } void -SubtitleContent::set_subtitle_scale (float s) +SubtitleContent::set_subtitle_scale (double s) { { boost::mutex::scoped_lock lm (_mutex); diff --git a/src/lib/subtitle_content.h b/src/lib/subtitle_content.h index 5eb4e500d..1092b7b1c 100644 --- a/src/lib/subtitle_content.h +++ b/src/lib/subtitle_content.h @@ -37,26 +37,26 @@ public: void as_xml (xmlpp::Node *) const; - void set_subtitle_offset (int); - void set_subtitle_scale (float); + void set_subtitle_offset (double); + void set_subtitle_scale (double); - int subtitle_offset () const { + double subtitle_offset () const { boost::mutex::scoped_lock lm (_mutex); return _subtitle_offset; } - float subtitle_scale () const { + double subtitle_scale () const { boost::mutex::scoped_lock lm (_mutex); return _subtitle_scale; } private: - /** y offset for placing subtitles, in source pixels; +ve is further down - the frame, -ve is further up. + /** y offset for placing subtitles, as a proportion of the container height; + +ve is further down the frame, -ve is further up. */ - int _subtitle_offset; + double _subtitle_offset; /** scale factor to apply to subtitles */ - float _subtitle_scale; + double _subtitle_scale; }; #endif diff --git a/src/lib/subtitle_decoder.cc b/src/lib/subtitle_decoder.cc index 0ffe5e501..c06f3d718 100644 --- a/src/lib/subtitle_decoder.cc +++ b/src/lib/subtitle_decoder.cc @@ -19,7 +19,6 @@ #include #include "subtitle_decoder.h" -#include "subtitle.h" using boost::shared_ptr; @@ -31,11 +30,10 @@ SubtitleDecoder::SubtitleDecoder (shared_ptr f) /** Called by subclasses when a subtitle is ready. - * s may be 0 to say that there is no current subtitle. - * @param s New current subtitle, or 0. + * Image may be 0 to say that there is no current subtitle. */ void -SubtitleDecoder::subtitle (shared_ptr s) +SubtitleDecoder::subtitle (shared_ptr image, dcpomatic::Rect rect, Time from, Time to) { - Subtitle (s); + Subtitle (image, rect, from, to); } diff --git a/src/lib/subtitle_decoder.h b/src/lib/subtitle_decoder.h index 0c299f61f..628f4d60d 100644 --- a/src/lib/subtitle_decoder.h +++ b/src/lib/subtitle_decoder.h @@ -19,6 +19,8 @@ #include #include "decoder.h" +#include "rect.h" +#include "types.h" class Film; class TimedSubtitle; @@ -28,8 +30,8 @@ class SubtitleDecoder : public virtual Decoder public: SubtitleDecoder (boost::shared_ptr); - boost::signals2::signal)> Subtitle; + boost::signals2::signal, dcpomatic::Rect, Time, Time)> Subtitle; protected: - void subtitle (boost::shared_ptr); + void subtitle (boost::shared_ptr, dcpomatic::Rect, Time, Time); }; diff --git a/src/lib/types.cc b/src/lib/types.cc index 78cb4cd64..035c8363d 100644 --- a/src/lib/types.cc +++ b/src/lib/types.cc @@ -32,25 +32,3 @@ bool operator!= (Crop const & a, Crop const & b) return !(a == b); } - -/** @param other A Rect. - * @return The intersection of this with `other'. - */ -dcpomatic::Rect -dcpomatic::Rect::intersection (Rect const & other) const -{ - int const tx = max (x, other.x); - int const ty = max (y, other.y); - - return Rect ( - tx, ty, - min (x + width, other.x + other.width) - tx, - min (y + height, other.y + other.height) - ty - ); -} - -bool -dcpomatic::Rect::contains (Position p) const -{ - return (p.x >= x && p.x <= (x + width) && p.y >= y && p.y <= (y + height)); -} diff --git a/src/lib/types.h b/src/lib/types.h index 33f8239d8..67384103d 100644 --- a/src/lib/types.h +++ b/src/lib/types.h @@ -53,66 +53,4 @@ struct Crop extern bool operator== (Crop const & a, Crop const & b); extern bool operator!= (Crop const & a, Crop const & b); -/** @struct Position - * @brief A position. - */ -struct Position -{ - Position () - : x (0) - , y (0) - {} - - Position (int x_, int y_) - : x (x_) - , y (y_) - {} - - /** x coordinate */ - int x; - /** y coordinate */ - int y; -}; - -namespace dcpomatic { - -/** @struct Rect - * @brief A rectangle. - */ -struct Rect -{ - Rect () - : x (0) - , y (0) - , width (0) - , height (0) - {} - - Rect (int x_, int y_, int w_, int h_) - : x (x_) - , y (y_) - , width (w_) - , height (h_) - {} - - int x; - int y; - int width; - int height; - - Position position () const { - return Position (x, y); - } - - libdcp::Size size () const { - return libdcp::Size (width, height); - } - - Rect intersection (Rect const & other) const; - - bool contains (Position) const; -}; - -} - #endif diff --git a/src/lib/video_decoder.cc b/src/lib/video_decoder.cc index 0616cd437..457cfe47b 100644 --- a/src/lib/video_decoder.cc +++ b/src/lib/video_decoder.cc @@ -18,10 +18,7 @@ */ #include "video_decoder.h" -#include "subtitle.h" -#include "film.h" #include "image.h" -#include "ratio.h" #include "i18n.h" diff --git a/src/lib/wscript b/src/lib/wscript index f646d9781..5c381b69c 100644 --- a/src/lib/wscript +++ b/src/lib/wscript @@ -44,7 +44,6 @@ sources = """ sndfile_content.cc sndfile_decoder.cc sound_processor.cc - subtitle.cc subtitle_content.cc subtitle_decoder.cc timer.cc diff --git a/src/wx/film_editor.cc b/src/wx/film_editor.cc index f63121201..e3c4af12c 100644 --- a/src/wx/film_editor.cc +++ b/src/wx/film_editor.cc @@ -426,7 +426,7 @@ FilmEditor::make_subtitle_panel () wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL); _subtitle_offset = new wxSpinCtrl (_subtitle_panel); s->Add (_subtitle_offset); - add_label_to_sizer (s, _subtitle_panel, _("pixels"), false); + add_label_to_sizer (s, _subtitle_panel, _("%"), false); grid->Add (s); } @@ -443,7 +443,7 @@ FilmEditor::make_subtitle_panel () _subtitle_stream = new wxChoice (_subtitle_panel, wxID_ANY); grid->Add (_subtitle_stream, 1, wxEXPAND); - _subtitle_offset->SetRange (-1024, 1024); + _subtitle_offset->SetRange (-100, 100); _subtitle_scale->SetRange (1, 1000); } @@ -532,7 +532,7 @@ FilmEditor::subtitle_offset_changed (wxCommandEvent &) return; } - c->set_subtitle_offset (_subtitle_offset->GetValue ()); + c->set_subtitle_offset (_subtitle_offset->GetValue() / 100.0); } void @@ -775,7 +775,7 @@ FilmEditor::film_content_changed (weak_ptr weak_content, int property) _dcp_sizer->Layout (); } } else if (property == SubtitleContentProperty::SUBTITLE_OFFSET) { - checked_set (_subtitle_offset, subtitle_content ? subtitle_content->subtitle_offset() : 0); + checked_set (_subtitle_offset, subtitle_content ? (subtitle_content->subtitle_offset() * 100) : 0); } else if (property == SubtitleContentProperty::SUBTITLE_SCALE) { checked_set (_subtitle_scale, subtitle_content ? (subtitle_content->subtitle_scale() * 100) : 100); } diff --git a/src/wx/timeline.cc b/src/wx/timeline.cc index bd2d314a4..f9223f19d 100644 --- a/src/wx/timeline.cc +++ b/src/wx/timeline.cc @@ -55,7 +55,7 @@ public: _timeline.force_redraw (bbox ()); } - virtual dcpomatic::Rect bbox () const = 0; + virtual dcpomatic::Rect bbox () const = 0; protected: virtual void do_paint (wxGraphicsContext *) = 0; @@ -68,7 +68,7 @@ protected: Timeline& _timeline; private: - dcpomatic::Rect _last_paint_bbox; + dcpomatic::Rect _last_paint_bbox; }; class ContentView : public View @@ -83,15 +83,15 @@ public: _content_connection = c->Changed.connect (bind (&ContentView::content_changed, this, _2)); } - dcpomatic::Rect bbox () const + dcpomatic::Rect bbox () const { shared_ptr film = _timeline.film (); shared_ptr content = _content.lock (); if (!film || !content) { - return dcpomatic::Rect (); + return dcpomatic::Rect (); } - return dcpomatic::Rect ( + return dcpomatic::Rect ( time_x (content->start ()) - 8, y_pos (_track) - 8, content->length () * _timeline.pixels_per_time_unit() + 16, @@ -243,9 +243,9 @@ public: , _y (y) {} - dcpomatic::Rect bbox () const + dcpomatic::Rect bbox () const { - return dcpomatic::Rect (0, _y - 4, _timeline.width(), 24); + return dcpomatic::Rect (0, _y - 4, _timeline.width(), 24); } void set_y (int y) @@ -476,7 +476,7 @@ void Timeline::left_down (wxMouseEvent& ev) { list >::iterator i = _views.begin(); - Position const p (ev.GetX(), ev.GetY()); + Position const p (ev.GetX(), ev.GetY()); while (i != _views.end() && !(*i)->bbox().contains (p)) { ++i; } @@ -545,7 +545,7 @@ Timeline::mouse_moved (wxMouseEvent& ev) } void -Timeline::force_redraw (dcpomatic::Rect const & r) +Timeline::force_redraw (dcpomatic::Rect const & r) { RefreshRect (wxRect (r.x, r.y, r.width, r.height), false); } diff --git a/src/wx/timeline.h b/src/wx/timeline.h index 5c25a6426..3e984bfe1 100644 --- a/src/wx/timeline.h +++ b/src/wx/timeline.h @@ -22,6 +22,7 @@ #include #include #include "util.h" +#include "rect.h" class Film; class View; @@ -36,7 +37,7 @@ public: boost::shared_ptr film () const; - void force_redraw (dcpomatic::Rect const &); + void force_redraw (dcpomatic::Rect const &); int x_offset () const { return 8; @@ -54,8 +55,8 @@ public: return _pixels_per_time_unit; } - Position tracks_position () const { - return Position (8, 8); + Position tracks_position () const { + return Position (8, 8); } int tracks () const; diff --git a/test/client_server_test.cc b/test/client_server_test.cc index 51b52331a..232190286 100644 --- a/test/client_server_test.cc +++ b/test/client_server_test.cc @@ -56,7 +56,7 @@ BOOST_AUTO_TEST_CASE (client_server_test) p += sub_image->stride()[0]; } - shared_ptr subtitle (new Subtitle (Position (50, 60), sub_image)); +// shared_ptr subtitle (new Subtitle (Position (50, 60), sub_image)); shared_ptr log (new FileLog ("build/test/client_server_test.log")); diff --git a/test/test.cc b/test/test.cc index d6c7842d7..0a682383a 100644 --- a/test/test.cc +++ b/test/test.cc @@ -36,7 +36,6 @@ #include "server.h" #include "cross.h" #include "job.h" -#include "subtitle.h" #include "scaler.h" #include "ffmpeg_decoder.h" #include "sndfile_decoder.h" -- cgit v1.2.3 From ad6c0bbec4f354f29fb968099ff1a0ce2e57c43a Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Fri, 12 Jul 2013 17:12:49 +0100 Subject: Remove unused RGBPlusAlphaImage; merge Image/SimpleImage. --- src/lib/ffmpeg_decoder.cc | 4 +- src/lib/filter_graph.cc | 2 +- src/lib/image.cc | 112 ++++++++++++----------------------------- src/lib/image.h | 90 ++++++--------------------------- src/lib/imagemagick_content.cc | 1 + src/lib/imagemagick_decoder.cc | 2 +- src/lib/player.cc | 4 +- src/lib/server.cc | 2 +- src/wx/film_viewer.cc | 2 +- test/client_server_test.cc | 4 +- test/image_test.cc | 16 +++--- test/make_black_test.cc | 2 +- test/pixel_formats_test.cc | 2 +- 13 files changed, 70 insertions(+), 173 deletions(-) (limited to 'src/lib/server.cc') diff --git a/src/lib/ffmpeg_decoder.cc b/src/lib/ffmpeg_decoder.cc index fddb70294..27009114c 100644 --- a/src/lib/ffmpeg_decoder.cc +++ b/src/lib/ffmpeg_decoder.cc @@ -412,7 +412,7 @@ FFmpegDecoder::decode_video_packet () a black frame. */ boost::shared_ptr black ( - new SimpleImage ( + new Image ( static_cast (_frame->format), libdcp::Size (video_codec_context()->width, video_codec_context()->height), true @@ -503,7 +503,7 @@ FFmpegDecoder::decode_subtitle_packet () throw DecodeError (_("non-bitmap subtitles not yet supported")); } - shared_ptr image (new SimpleImage (PIX_FMT_RGBA, libdcp::Size (rect->w, rect->h), true)); + shared_ptr image (new Image (PIX_FMT_RGBA, libdcp::Size (rect->w, rect->h), true)); /* Start of the first line in the subtitle */ uint8_t* sub_p = rect->pict.data[0]; diff --git a/src/lib/filter_graph.cc b/src/lib/filter_graph.cc index cc16b279d..3366f8d1b 100644 --- a/src/lib/filter_graph.cc +++ b/src/lib/filter_graph.cc @@ -146,7 +146,7 @@ FilterGraph::process (AVFrame* frame) break; } - images.push_back (shared_ptr (new SimpleImage (_frame))); + images.push_back (shared_ptr (new Image (_frame))); av_frame_unref (_frame); } diff --git a/src/lib/image.cc b/src/lib/image.cc index c11bcbb8d..62c26defb 100644 --- a/src/lib/image.cc +++ b/src/lib/image.cc @@ -18,43 +18,26 @@ */ /** @file src/image.cc - * @brief A set of classes to describe video images. + * @brief A class to describe a video image. */ -#include -#include #include -#include -#include -#include -#include extern "C" { -#include -#include #include -#include -#include #include #include +#include } #include "image.h" #include "exceptions.h" #include "scaler.h" -#include "i18n.h" - using std::string; using std::min; using std::cout; using boost::shared_ptr; using libdcp::Size; -void -Image::swap (Image& other) -{ - std::swap (_pixel_format, other._pixel_format); -} - int Image::line_factor (int n) const { @@ -64,7 +47,7 @@ Image::line_factor (int n) const AVPixFmtDescriptor const * d = av_pix_fmt_desc_get(_pixel_format); if (!d) { - throw PixelFormatError (N_("lines()"), _pixel_format); + throw PixelFormatError ("lines()", _pixel_format); } return pow (2.0f, d->log2_chroma_h); @@ -85,7 +68,7 @@ Image::components () const { AVPixFmtDescriptor const * d = av_pix_fmt_desc_get(_pixel_format); if (!d) { - throw PixelFormatError (N_("components()"), _pixel_format); + throw PixelFormatError ("components()", _pixel_format); } if ((d->flags & PIX_FMT_PLANAR) == 0) { @@ -104,7 +87,7 @@ Image::scale (libdcp::Size out_size, Scaler const * scaler, bool result_aligned) */ assert (aligned ()); - shared_ptr scaled (new SimpleImage (pixel_format(), out_size, result_aligned)); + shared_ptr scaled (new Image (pixel_format(), out_size, result_aligned)); struct SwsContext* scale_context = sws_getContext ( size().width, size().height, pixel_format(), @@ -137,7 +120,7 @@ Image::scale_and_convert_to_rgb (libdcp::Size out_size, Scaler const * scaler, b */ assert (aligned ()); - shared_ptr rgb (new SimpleImage (PIX_FMT_RGB24, out_size, result_aligned)); + shared_ptr rgb (new Image (PIX_FMT_RGB24, out_size, result_aligned)); struct SwsContext* scale_context = sws_getContext ( size().width, size().height, pixel_format(), @@ -165,7 +148,7 @@ Image::scale_and_convert_to_rgb (libdcp::Size out_size, Scaler const * scaler, b shared_ptr Image::post_process (string pp, bool aligned) const { - shared_ptr out (new SimpleImage (pixel_format(), size (), aligned)); + shared_ptr out (new Image (pixel_format(), size (), aligned)); int pp_format = 0; switch (pixel_format()) { @@ -184,7 +167,7 @@ Image::post_process (string pp, bool aligned) const case PIX_FMT_YUV444P10LE: pp_format = PP_FORMAT_444; default: - throw PixelFormatError (N_("post_process"), pixel_format()); + throw PixelFormatError ("post_process", pixel_format()); } pp_mode* mode = pp_get_mode_by_name_and_quality (pp.c_str (), PP_QUALITY_MAX); @@ -210,7 +193,7 @@ Image::crop (Crop crop, bool aligned) const cropped_size.width -= crop.left + crop.right; cropped_size.height -= crop.top + crop.bottom; - shared_ptr out (new SimpleImage (pixel_format(), cropped_size, aligned)); + shared_ptr out (new Image (pixel_format(), cropped_size, aligned)); for (int c = 0; c < components(); ++c) { int const crop_left_in_bytes = bytes_per_pixel(c) * crop.left; @@ -331,7 +314,7 @@ Image::make_black () } default: - throw PixelFormatError (N_("make_black()"), _pixel_format); + throw PixelFormatError ("make_black()", _pixel_format); } } @@ -416,7 +399,7 @@ Image::bytes_per_pixel (int c) const { AVPixFmtDescriptor const * d = av_pix_fmt_desc_get(_pixel_format); if (!d) { - throw PixelFormatError (N_("lines()"), _pixel_format); + throw PixelFormatError ("lines()", _pixel_format); } if (c >= components()) { @@ -444,14 +427,14 @@ Image::bytes_per_pixel (int c) const return bpp[c]; } -/** Construct a SimpleImage of a given size and format, allocating memory +/** Construct a Image of a given size and format, allocating memory * as required. * * @param p Pixel format. * @param s Size in pixels. */ -SimpleImage::SimpleImage (AVPixelFormat p, libdcp::Size s, bool aligned) - : Image (p) +Image::Image (AVPixelFormat p, libdcp::Size s, bool aligned) + : _pixel_format (p) , _size (s) , _aligned (aligned) { @@ -459,7 +442,7 @@ SimpleImage::SimpleImage (AVPixelFormat p, libdcp::Size s, bool aligned) } void -SimpleImage::allocate () +Image::allocate () { _data = (uint8_t **) av_malloc (4 * sizeof (uint8_t *)); _data[0] = _data[1] = _data[2] = _data[3] = 0; @@ -477,8 +460,8 @@ SimpleImage::allocate () } } -SimpleImage::SimpleImage (SimpleImage const & other) - : Image (other) +Image::Image (Image const & other) + : _pixel_format (other._pixel_format) , _size (other._size) , _aligned (other._aligned) { @@ -495,8 +478,8 @@ SimpleImage::SimpleImage (SimpleImage const & other) } } -SimpleImage::SimpleImage (AVFrame* frame) - : Image (static_cast (frame->format)) +Image::Image (AVFrame* frame) + : _pixel_format (static_cast (frame->format)) , _size (frame->width, frame->height) , _aligned (true) { @@ -514,8 +497,8 @@ SimpleImage::SimpleImage (AVFrame* frame) } } -SimpleImage::SimpleImage (shared_ptr other, bool aligned) - : Image (*other.get()) +Image::Image (shared_ptr other, bool aligned) + : _pixel_format (other->_pixel_format) , _size (other->size()) , _aligned (aligned) { @@ -533,23 +516,22 @@ SimpleImage::SimpleImage (shared_ptr other, bool aligned) } } -SimpleImage& -SimpleImage::operator= (SimpleImage const & other) +Image& +Image::operator= (Image const & other) { if (this == &other) { return *this; } - SimpleImage tmp (other); + Image tmp (other); swap (tmp); return *this; } void -SimpleImage::swap (SimpleImage & other) +Image::swap (Image & other) { - Image::swap (other); - + std::swap (_pixel_format, other._pixel_format); std::swap (_size, other._size); for (int i = 0; i < 4; ++i) { @@ -561,8 +543,8 @@ SimpleImage::swap (SimpleImage & other) std::swap (_aligned, other._aligned); } -/** Destroy a SimpleImage */ -SimpleImage::~SimpleImage () +/** Destroy a Image */ +Image::~Image () { for (int i = 0; i < components(); ++i) { av_free (_data[i]); @@ -574,60 +556,32 @@ SimpleImage::~SimpleImage () } uint8_t ** -SimpleImage::data () const +Image::data () const { return _data; } int * -SimpleImage::line_size () const +Image::line_size () const { return _line_size; } int * -SimpleImage::stride () const +Image::stride () const { return _stride; } libdcp::Size -SimpleImage::size () const +Image::size () const { return _size; } bool -SimpleImage::aligned () const +Image::aligned () const { return _aligned; } -RGBPlusAlphaImage::RGBPlusAlphaImage (shared_ptr im) - : SimpleImage (im->pixel_format(), im->size(), false) -{ - assert (im->pixel_format() == PIX_FMT_RGBA); - - _alpha = (uint8_t *) av_malloc (im->size().width * im->size().height); - - uint8_t* in = im->data()[0]; - uint8_t* out = data()[0]; - uint8_t* out_alpha = _alpha; - for (int y = 0; y < im->size().height; ++y) { - uint8_t* in_r = in; - for (int x = 0; x < im->size().width; ++x) { - *out++ = *in_r++; - *out++ = *in_r++; - *out++ = *in_r++; - *out_alpha++ = *in_r++; - } - - in += im->stride()[0]; - } -} - -RGBPlusAlphaImage::~RGBPlusAlphaImage () -{ - av_free (_alpha); -} - diff --git a/src/lib/image.h b/src/lib/image.h index d40ba77b4..ab809cc46 100644 --- a/src/lib/image.h +++ b/src/lib/image.h @@ -35,39 +35,22 @@ extern "C" { #include "position.h" class Scaler; -class SimpleImage; -/** @class Image - * @brief Parent class for wrappers of some image, in some format, that - * can present a set of components and a size in pixels. - * - * This class also has some conversion / processing methods. - * - * The main point of this class (and its subclasses) is to abstract - * details of FFmpeg's memory management and varying data formats. - */ class Image { public: - Image (AVPixelFormat p) - : _pixel_format (p) - {} + Image (AVPixelFormat, libdcp::Size, bool); + Image (AVFrame *); + Image (Image const &); + Image (boost::shared_ptr, bool); + Image& operator= (Image const &); + ~Image (); - virtual ~Image () {} - - /** @return Array of pointers to arrays of the component data */ - virtual uint8_t ** data () const = 0; - - /** @return Array of sizes of the data in each line, in bytes (without any alignment padding bytes) */ - virtual int * line_size () const = 0; - - /** @return Array of strides for each line (including any alignment padding bytes) */ - virtual int * stride () const = 0; - - /** @return Size of the image, in pixels */ - virtual libdcp::Size size () const = 0; - - virtual bool aligned () const = 0; + uint8_t ** data () const; + int * line_size () const; + int * stride () const; + libdcp::Size size () const; + bool aligned () const; int components () const; int line_factor (int) const; @@ -89,43 +72,16 @@ public: return _pixel_format; } -protected: - virtual void swap (Image &); - float bytes_per_pixel (int) const; - - friend class pixel_formats_test; - private: + friend class pixel_formats_test; + + void allocate (); + void swap (Image &); + float bytes_per_pixel (int) const; void yuv_16_black (uint16_t); static uint16_t swap_16 (uint16_t); AVPixelFormat _pixel_format; ///< FFmpeg's way of describing the pixel format of this Image -}; - -/** @class SimpleImage - * @brief An Image for which memory is allocated using a `simple' av_malloc(). - */ -class SimpleImage : public Image -{ -public: - SimpleImage (AVPixelFormat, libdcp::Size, bool); - SimpleImage (AVFrame *); - SimpleImage (SimpleImage const &); - SimpleImage (boost::shared_ptr, bool); - SimpleImage& operator= (SimpleImage const &); - ~SimpleImage (); - - uint8_t ** data () const; - int * line_size () const; - int * stride () const; - libdcp::Size size () const; - bool aligned () const; - -protected: - void allocate (); - void swap (SimpleImage &); - -private: libdcp::Size _size; ///< size in pixels uint8_t** _data; ///< array of pointers to components int* _line_size; ///< array of sizes of the data in each line, in pixels (without any alignment padding bytes) @@ -133,18 +89,4 @@ private: bool _aligned; }; -class RGBPlusAlphaImage : public SimpleImage -{ -public: - RGBPlusAlphaImage (boost::shared_ptr); - ~RGBPlusAlphaImage (); - - uint8_t* alpha () const { - return _alpha; - } - -private: - uint8_t* _alpha; -}; - #endif diff --git a/src/lib/imagemagick_content.cc b/src/lib/imagemagick_content.cc index 42e3776f5..8e858d0d1 100644 --- a/src/lib/imagemagick_content.cc +++ b/src/lib/imagemagick_content.cc @@ -113,4 +113,5 @@ ImageMagickContent::identifier () const stringstream s; s << VideoContent::identifier (); s << "_" << video_length(); + return s.str (); } diff --git a/src/lib/imagemagick_decoder.cc b/src/lib/imagemagick_decoder.cc index 6178443cf..ee50f3fb1 100644 --- a/src/lib/imagemagick_decoder.cc +++ b/src/lib/imagemagick_decoder.cc @@ -55,7 +55,7 @@ ImageMagickDecoder::pass () Magick::Image* magick_image = new Magick::Image (_imagemagick_content->file().string ()); _video_size = libdcp::Size (magick_image->columns(), magick_image->rows()); - _image.reset (new SimpleImage (PIX_FMT_RGB24, _video_size.get(), false)); + _image.reset (new Image (PIX_FMT_RGB24, _video_size.get(), false)); using namespace MagickCore; diff --git a/src/lib/player.cc b/src/lib/player.cc index 61764a39d..8532b5417 100644 --- a/src/lib/player.cc +++ b/src/lib/player.cc @@ -232,7 +232,7 @@ Player::process_video (weak_ptr weak_piece, shared_ptr image if (image_size != _video_container_size) { assert (image_size.width <= _video_container_size.width); assert (image_size.height <= _video_container_size.height); - shared_ptr im (new SimpleImage (PIX_FMT_RGB24, _video_container_size, true)); + shared_ptr im (new Image (PIX_FMT_RGB24, _video_container_size, true)); im->make_black (); im->copy (work_image, Position ((_video_container_size.width - image_size.width) / 2, (_video_container_size.height - image_size.height) / 2)); work_image = im; @@ -482,7 +482,7 @@ void Player::set_video_container_size (libdcp::Size s) { _video_container_size = s; - _black_frame.reset (new SimpleImage (PIX_FMT_RGB24, _video_container_size, true)); + _black_frame.reset (new Image (PIX_FMT_RGB24, _video_container_size, true)); _black_frame->make_black (); } diff --git a/src/lib/server.cc b/src/lib/server.cc index 40d1c4c0c..b38e82a07 100644 --- a/src/lib/server.cc +++ b/src/lib/server.cc @@ -110,7 +110,7 @@ Server::process (shared_ptr socket) /* This checks that colour_lut_index is within range */ colour_lut_index_to_name (colour_lut_index); - shared_ptr image (new SimpleImage (PIX_FMT_RGB24, size, true)); + shared_ptr image (new Image (PIX_FMT_RGB24, size, true)); image->read_from_socket (socket); diff --git a/src/wx/film_viewer.cc b/src/wx/film_viewer.cc index 15c23e064..2cc63aea4 100644 --- a/src/wx/film_viewer.cc +++ b/src/wx/film_viewer.cc @@ -174,7 +174,7 @@ FilmViewer::paint_panel (wxPaintEvent &) return; } - shared_ptr packed_frame (new SimpleImage (_frame, false)); + shared_ptr packed_frame (new Image (_frame, false)); wxImage frame (_out_size.width, _out_size.height, packed_frame->data()[0], true); wxBitmap frame_bitmap (frame); diff --git a/test/client_server_test.cc b/test/client_server_test.cc index 232190286..50add352f 100644 --- a/test/client_server_test.cc +++ b/test/client_server_test.cc @@ -30,7 +30,7 @@ do_remote_encode (shared_ptr frame, ServerDescription* descriptio BOOST_AUTO_TEST_CASE (client_server_test) { - shared_ptr image (new SimpleImage (PIX_FMT_RGB24, libdcp::Size (1998, 1080), true)); + shared_ptr image (new Image (PIX_FMT_RGB24, libdcp::Size (1998, 1080), true)); uint8_t* p = image->data()[0]; for (int y = 0; y < 1080; ++y) { @@ -43,7 +43,7 @@ BOOST_AUTO_TEST_CASE (client_server_test) p += image->stride()[0]; } - shared_ptr sub_image (new SimpleImage (PIX_FMT_RGBA, libdcp::Size (100, 200), true)); + shared_ptr sub_image (new Image (PIX_FMT_RGBA, libdcp::Size (100, 200), true)); p = sub_image->data()[0]; for (int y = 0; y < 200; ++y) { uint8_t* q = p; diff --git a/test/image_test.cc b/test/image_test.cc index b74531c46..8dc289602 100644 --- a/test/image_test.cc +++ b/test/image_test.cc @@ -1,7 +1,7 @@ BOOST_AUTO_TEST_CASE (aligned_image_test) { - SimpleImage* s = new SimpleImage (PIX_FMT_RGB24, libdcp::Size (50, 50), true); + Image* s = new Image (PIX_FMT_RGB24, libdcp::Size (50, 50), true); BOOST_CHECK_EQUAL (s->components(), 1); /* 160 is 150 aligned to the nearest 32 bytes */ BOOST_CHECK_EQUAL (s->stride()[0], 160); @@ -12,7 +12,7 @@ BOOST_AUTO_TEST_CASE (aligned_image_test) BOOST_CHECK (!s->data()[3]); /* copy constructor */ - SimpleImage* t = new SimpleImage (*s); + Image* t = new Image (*s); BOOST_CHECK_EQUAL (t->components(), 1); BOOST_CHECK_EQUAL (t->stride()[0], 160); BOOST_CHECK_EQUAL (t->line_size()[0], 150); @@ -28,7 +28,7 @@ BOOST_AUTO_TEST_CASE (aligned_image_test) BOOST_CHECK (t->stride()[0] == s->stride()[0]); /* assignment operator */ - SimpleImage* u = new SimpleImage (PIX_FMT_YUV422P, libdcp::Size (150, 150), false); + Image* u = new Image (PIX_FMT_YUV422P, libdcp::Size (150, 150), false); *u = *s; BOOST_CHECK_EQUAL (u->components(), 1); BOOST_CHECK_EQUAL (u->stride()[0], 160); @@ -51,7 +51,7 @@ BOOST_AUTO_TEST_CASE (aligned_image_test) BOOST_AUTO_TEST_CASE (compact_image_test) { - SimpleImage* s = new SimpleImage (PIX_FMT_RGB24, libdcp::Size (50, 50), false); + Image* s = new Image (PIX_FMT_RGB24, libdcp::Size (50, 50), false); BOOST_CHECK_EQUAL (s->components(), 1); BOOST_CHECK_EQUAL (s->stride()[0], 50 * 3); BOOST_CHECK_EQUAL (s->line_size()[0], 50 * 3); @@ -61,7 +61,7 @@ BOOST_AUTO_TEST_CASE (compact_image_test) BOOST_CHECK (!s->data()[3]); /* copy constructor */ - SimpleImage* t = new SimpleImage (*s); + Image* t = new Image (*s); BOOST_CHECK_EQUAL (t->components(), 1); BOOST_CHECK_EQUAL (t->stride()[0], 50 * 3); BOOST_CHECK_EQUAL (t->line_size()[0], 50 * 3); @@ -77,7 +77,7 @@ BOOST_AUTO_TEST_CASE (compact_image_test) BOOST_CHECK (t->stride()[0] == s->stride()[0]); /* assignment operator */ - SimpleImage* u = new SimpleImage (PIX_FMT_YUV422P, libdcp::Size (150, 150), true); + Image* u = new Image (PIX_FMT_YUV422P, libdcp::Size (150, 150), true); *u = *s; BOOST_CHECK_EQUAL (u->components(), 1); BOOST_CHECK_EQUAL (u->stride()[0], 50 * 3); @@ -101,7 +101,7 @@ BOOST_AUTO_TEST_CASE (compact_image_test) BOOST_AUTO_TEST_CASE (crop_image_test) { /* This was to check out a bug with valgrind, and is probably not very useful */ - shared_ptr image (new SimpleImage (PIX_FMT_YUV420P, libdcp::Size (16, 16), true)); + shared_ptr image (new Image (PIX_FMT_YUV420P, libdcp::Size (16, 16), true)); image->make_black (); Crop crop; crop.top = 3; @@ -114,7 +114,7 @@ BOOST_AUTO_TEST_CASE (crop_image_test) BOOST_AUTO_TEST_CASE (crop_image_test2) { /* Here's a 1998 x 1080 image which is black */ - shared_ptr image (new SimpleImage (PIX_FMT_YUV420P, libdcp::Size (1998, 1080), true)); + shared_ptr image (new Image (PIX_FMT_YUV420P, libdcp::Size (1998, 1080), true)); image->make_black (); /* Crop it by 1 pixel */ diff --git a/test/make_black_test.cc b/test/make_black_test.cc index 9bec00651..4c2822514 100644 --- a/test/make_black_test.cc +++ b/test/make_black_test.cc @@ -41,7 +41,7 @@ BOOST_AUTO_TEST_CASE (make_black_test) int N = 0; for (list::const_iterator i = pix_fmts.begin(); i != pix_fmts.end(); ++i) { - boost::shared_ptr foo (new SimpleImage (*i, in_size, true)); + boost::shared_ptr foo (new Image (*i, in_size, true)); foo->make_black (); boost::shared_ptr bar = foo->scale_and_convert_to_rgb (out_size, Scaler::from_id ("bicubic"), true); diff --git a/test/pixel_formats_test.cc b/test/pixel_formats_test.cc index fb2278fdb..ccdda3317 100644 --- a/test/pixel_formats_test.cc +++ b/test/pixel_formats_test.cc @@ -63,7 +63,7 @@ BOOST_AUTO_TEST_CASE (pixel_formats_test) f->height = 480; f->format = static_cast (i->format); av_frame_get_buffer (f, true); - SimpleImage t (f); + Image t (f); BOOST_CHECK_EQUAL(t.components(), i->components); BOOST_CHECK_EQUAL(t.lines(0), i->lines[0]); BOOST_CHECK_EQUAL(t.lines(1), i->lines[1]); -- cgit v1.2.3 From 5f1046a2164fff00a6fc74aecf4cacbca531d415 Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Fri, 12 Jul 2013 23:12:41 +0100 Subject: Remove entirely untested colour LUT options. --- src/lib/dcp_video_frame.cc | 21 +++++---------------- src/lib/dcp_video_frame.h | 3 +-- src/lib/encoder.cc | 2 +- src/lib/film.cc | 17 +---------------- src/lib/film.h | 12 ------------ src/lib/server.cc | 6 +----- src/lib/util.cc | 17 ----------------- src/lib/util.h | 1 - src/wx/film_editor.cc | 25 ------------------------- src/wx/film_editor.h | 2 -- test/client_server_test.cc | 1 - 11 files changed, 9 insertions(+), 98 deletions(-) (limited to 'src/lib/server.cc') diff --git a/src/lib/dcp_video_frame.cc b/src/lib/dcp_video_frame.cc index 39334d3c7..22a7c5795 100644 --- a/src/lib/dcp_video_frame.cc +++ b/src/lib/dcp_video_frame.cc @@ -73,17 +73,15 @@ using libdcp::Size; /** Construct a DCP video frame. * @param input Input image. * @param f Index of the frame within the DCP. - * @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 image, int f, int dcp_fps, int clut, int bw, shared_ptr l + shared_ptr image, int f, int dcp_fps, int bw, shared_ptr l ) : _image (image) , _frame (f) , _frames_per_second (dcp_fps) - , _colour_lut (clut) , _j2k_bandwidth (bw) , _log (l) , _parameters (0) @@ -116,19 +114,11 @@ DCPVideoFrame::~DCPVideoFrame () shared_ptr DCPVideoFrame::encode_locally () { - /* In sRGB / Rec709 gamma LUT */ - shared_ptr lut_in; - if (_colour_lut == 0) { - lut_in = libdcp::SRGBLinearisedGammaLUT::cache.get (12, 2.4); - } else { - lut_in = libdcp::Rec709LinearisedGammaLUT::cache.get (12, 1 / 0.45); - } - - /* Out DCI gamma LUT */ - shared_ptr lut_out = libdcp::GammaLUT::cache.get (16, 1 / 2.6); - shared_ptr xyz = libdcp::rgb_to_xyz ( - _image, lut_in, lut_out, _colour_lut == 0 ? libdcp::colour_matrix::srgb_to_xyz : libdcp::colour_matrix::rec709_to_xyz + _image, + libdcp::SRGBLinearisedGammaLUT::cache.get (12, 2.4), + libdcp::GammaLUT::cache.get (16, 1 / 2.6), + libdcp::colour_matrix::srgb_to_xyz ); /* Set the max image and component sizes based on frame_rate */ @@ -234,7 +224,6 @@ DCPVideoFrame::encode_remotely (ServerDescription const * serv) << N_("height ") << _image->size().height << N_("\n") << N_("frame ") << _frame << 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"); _log->log (String::compose ( diff --git a/src/lib/dcp_video_frame.h b/src/lib/dcp_video_frame.h index b0b662e5b..25a3e9926 100644 --- a/src/lib/dcp_video_frame.h +++ b/src/lib/dcp_video_frame.h @@ -105,7 +105,7 @@ public: class DCPVideoFrame { public: - DCPVideoFrame (boost::shared_ptr, int, int, int, int, boost::shared_ptr); + DCPVideoFrame (boost::shared_ptr, int, int, int, boost::shared_ptr); ~DCPVideoFrame (); boost::shared_ptr encode_locally (); @@ -119,7 +119,6 @@ private: 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 int _j2k_bandwidth; ///< J2K bandwidth to use boost::shared_ptr _log; ///< log diff --git a/src/lib/encoder.cc b/src/lib/encoder.cc index ed14f2755..718ae55a4 100644 --- a/src/lib/encoder.cc +++ b/src/lib/encoder.cc @@ -203,7 +203,7 @@ Encoder::process_video (shared_ptr image, bool same) _queue.push_back (shared_ptr ( new DCPVideoFrame ( image, _video_frames_out, _film->dcp_video_frame_rate(), - _film->colour_lut(), _film->j2k_bandwidth(), _film->log() + _film->j2k_bandwidth(), _film->log() ) )); diff --git a/src/lib/film.cc b/src/lib/film.cc index a49e549a7..f306006c9 100644 --- a/src/lib/film.cc +++ b/src/lib/film.cc @@ -94,7 +94,6 @@ Film::Film (string d) , _container (Config::instance()->default_container ()) , _scaler (Scaler::from_id ("bicubic")) , _with_subtitles (false) - , _colour_lut (0) , _j2k_bandwidth (200000000) , _dci_metadata (Config::instance()->default_dci_metadata ()) , _dcp_video_frame_rate (24) @@ -140,7 +139,6 @@ Film::Film (Film const & o) , _container (o._container) , _scaler (o._scaler) , _with_subtitles (o._with_subtitles) - , _colour_lut (o._colour_lut) , _j2k_bandwidth (o._j2k_bandwidth) , _dci_metadata (o._dci_metadata) , _dcp_video_frame_rate (o._dcp_video_frame_rate) @@ -161,8 +159,7 @@ Film::video_identifier () const << "_" << _playlist->video_identifier() << "_" << _dcp_video_frame_rate << "_" << scaler()->id() - << "_" << j2k_bandwidth() - << "_" << lexical_cast (colour_lut()); + << "_" << j2k_bandwidth(); return s.str (); } @@ -344,7 +341,6 @@ Film::write_metadata () const root->add_child("Scaler")->add_child_text (_scaler->id ()); root->add_child("WithSubtitles")->add_child_text (_with_subtitles ? "1" : "0"); - root->add_child("ColourLUT")->add_child_text (lexical_cast (_colour_lut)); root->add_child("J2KBandwidth")->add_child_text (lexical_cast (_j2k_bandwidth)); _dci_metadata.as_xml (root->add_child ("DCIMetadata")); root->add_child("DCPVideoFrameRate")->add_child_text (lexical_cast (_dcp_video_frame_rate)); @@ -389,7 +385,6 @@ Film::read_metadata () _scaler = Scaler::from_id (f.string_child ("Scaler")); _with_subtitles = f.bool_child ("WithSubtitles"); - _colour_lut = f.number_child ("ColourLUT"); _j2k_bandwidth = f.number_child ("J2KBandwidth"); _dci_metadata = DCIMetadata (f.node_child ("DCIMetadata")); _dcp_video_frame_rate = f.number_child ("DCPVideoFrameRate"); @@ -585,16 +580,6 @@ Film::set_with_subtitles (bool w) signal_changed (WITH_SUBTITLES); } -void -Film::set_colour_lut (int i) -{ - { - boost::mutex::scoped_lock lm (_state_mutex); - _colour_lut = i; - } - signal_changed (COLOUR_LUT); -} - void Film::set_j2k_bandwidth (int b) { diff --git a/src/lib/film.h b/src/lib/film.h index c107541a0..bf89c6f2c 100644 --- a/src/lib/film.h +++ b/src/lib/film.h @@ -135,7 +135,6 @@ public: CONTAINER, SCALER, WITH_SUBTITLES, - COLOUR_LUT, J2K_BANDWIDTH, DCI_METADATA, DCP_VIDEO_FRAME_RATE, @@ -180,11 +179,6 @@ public: return _with_subtitles; } - int colour_lut () const { - boost::mutex::scoped_lock lm (_state_mutex); - return _colour_lut; - } - int j2k_bandwidth () const { boost::mutex::scoped_lock lm (_state_mutex); return _j2k_bandwidth; @@ -218,7 +212,6 @@ public: void set_container (Ratio const *); void set_scaler (Scaler const *); void set_with_subtitles (bool); - void set_colour_lut (int); void set_j2k_bandwidth (int); void set_dci_metadata (DCIMetadata); void set_dcp_video_frame_rate (int); @@ -266,11 +259,6 @@ private: Scaler const * _scaler; /** True if subtitles should be shown for this film */ bool _with_subtitles; - /** index of colour LUT to use when converting RGB to XYZ. - * 0: sRGB - * 1: Rec 709 - */ - int _colour_lut; /** bandwidth for J2K files in bits per second */ int _j2k_bandwidth; /** DCI naming stuff */ diff --git a/src/lib/server.cc b/src/lib/server.cc index b38e82a07..9af0883a7 100644 --- a/src/lib/server.cc +++ b/src/lib/server.cc @@ -104,18 +104,14 @@ Server::process (shared_ptr socket) 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); - shared_ptr image (new Image (PIX_FMT_RGB24, size, true)); image->read_from_socket (socket); DCPVideoFrame dcp_video_frame ( - image, frame, frames_per_second, colour_lut_index, j2k_bandwidth, _log + image, frame, frames_per_second, j2k_bandwidth, _log ); shared_ptr encoded = dcp_video_frame.encode_locally (); diff --git a/src/lib/util.cc b/src/lib/util.cc index 53c457898..305aae4f8 100644 --- a/src/lib/util.cc +++ b/src/lib/util.cc @@ -457,23 +457,6 @@ dcp_audio_frame_rate (int fs) return 96000; } -/** @param index Colour LUT index. - * @return Human-readable name. - */ -string -colour_lut_index_to_name (int index) -{ - switch (index) { - case 0: - return _("sRGB"); - case 1: - return _("Rec 709"); - } - - assert (false); - return N_(""); -} - Socket::Socket (int timeout) : _deadline (_io_service) , _socket (_io_service) diff --git a/src/lib/util.h b/src/lib/util.h index 57dc0f783..d9c88293e 100644 --- a/src/lib/util.h +++ b/src/lib/util.h @@ -107,7 +107,6 @@ struct FrameRateConversion }; extern int dcp_audio_frame_rate (int); -extern std::string colour_lut_index_to_name (int index); extern int stride_round_up (int, int const *, int); extern int stride_lookup (int c, int const * stride); extern std::multimap read_key_value (std::istream& s); diff --git a/src/wx/film_editor.cc b/src/wx/film_editor.cc index 65497859c..0828d5b79 100644 --- a/src/wx/film_editor.cc +++ b/src/wx/film_editor.cc @@ -221,7 +221,6 @@ FilmEditor::connect_to_widgets () _with_subtitles->Connect (wxID_ANY, wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler (FilmEditor::with_subtitles_toggled), 0, this); _subtitle_offset->Connect (wxID_ANY, wxEVT_COMMAND_SPINCTRL_UPDATED, wxCommandEventHandler (FilmEditor::subtitle_offset_changed), 0, this); _subtitle_scale->Connect (wxID_ANY, wxEVT_COMMAND_SPINCTRL_UPDATED, wxCommandEventHandler (FilmEditor::subtitle_scale_changed), 0, this); - _colour_lut->Connect (wxID_ANY, wxEVT_COMMAND_CHOICE_SELECTED, wxCommandEventHandler (FilmEditor::colour_lut_changed), 0, this); _j2k_bandwidth->Connect (wxID_ANY, wxEVT_COMMAND_SPINCTRL_UPDATED, wxCommandEventHandler (FilmEditor::j2k_bandwidth_changed), 0, this); _audio_gain->Connect (wxID_ANY, wxEVT_COMMAND_SPINCTRL_UPDATED, wxCommandEventHandler (FilmEditor::audio_gain_changed), 0, this); _audio_gain_calculate_button->Connect ( @@ -292,15 +291,6 @@ FilmEditor::make_video_panel () } ++r; - add_label_to_grid_bag_sizer (grid, _video_panel, _("Colour look-up table"), true, wxGBPosition (r, 0)); - _colour_lut = new wxChoice (_video_panel, wxID_ANY); - for (int i = 0; i < 2; ++i) { - _colour_lut->Append (std_to_wx (colour_lut_index_to_name (i))); - } - _colour_lut->SetSelection (0); - grid->Add (_colour_lut, wxGBPosition (r, 1), wxDefaultSpan, wxEXPAND); - ++r; - _left_crop->SetRange (0, 1024); _top_crop->SetRange (0, 1024); _right_crop->SetRange (0, 1024); @@ -554,16 +544,6 @@ FilmEditor::subtitle_scale_changed (wxCommandEvent &) c->set_subtitle_scale (_subtitle_scale->GetValue() / 100.0); } -void -FilmEditor::colour_lut_changed (wxCommandEvent &) -{ - if (!_film) { - return; - } - - _film->set_colour_lut (_colour_lut->GetSelection ()); -} - void FilmEditor::j2k_bandwidth_changed (wxCommandEvent &) { @@ -646,9 +626,6 @@ FilmEditor::film_changed (Film::Property p) setup_subtitle_control_sensitivity (); setup_dcp_name (); break; - case Film::COLOUR_LUT: - checked_set (_colour_lut, _film->colour_lut ()); - break; case Film::J2K_BANDWIDTH: checked_set (_j2k_bandwidth, double (_film->j2k_bandwidth()) / 1e6); break; @@ -885,7 +862,6 @@ FilmEditor::set_film (shared_ptr f) film_changed (Film::CONTAINER); film_changed (Film::SCALER); film_changed (Film::WITH_SUBTITLES); - film_changed (Film::COLOUR_LUT); film_changed (Film::J2K_BANDWIDTH); film_changed (Film::DCI_METADATA); film_changed (Film::DCP_VIDEO_FRAME_RATE); @@ -917,7 +893,6 @@ FilmEditor::set_things_sensitive (bool s) _dcp_content_type->Enable (s); _dcp_frame_rate->Enable (s); _dcp_audio_channels->Enable (s); - _colour_lut->Enable (s); _j2k_bandwidth->Enable (s); _audio_gain->Enable (s); _audio_gain_calculate_button->Enable (s); diff --git a/src/wx/film_editor.h b/src/wx/film_editor.h index 100e47b5b..f2aaae04d 100644 --- a/src/wx/film_editor.h +++ b/src/wx/film_editor.h @@ -83,7 +83,6 @@ private: void with_subtitles_toggled (wxCommandEvent &); void subtitle_offset_changed (wxCommandEvent &); void subtitle_scale_changed (wxCommandEvent &); - void colour_lut_changed (wxCommandEvent &); void j2k_bandwidth_changed (wxCommandEvent &); void dcp_frame_rate_changed (wxCommandEvent &); void best_dcp_frame_rate_clicked (wxCommandEvent &); @@ -164,7 +163,6 @@ private: wxCheckBox* _with_subtitles; wxSpinCtrl* _subtitle_offset; wxSpinCtrl* _subtitle_scale; - wxChoice* _colour_lut; wxSpinCtrl* _j2k_bandwidth; wxChoice* _dcp_content_type; wxChoice* _dcp_frame_rate; diff --git a/test/client_server_test.cc b/test/client_server_test.cc index 50add352f..f3d72c2fc 100644 --- a/test/client_server_test.cc +++ b/test/client_server_test.cc @@ -65,7 +65,6 @@ BOOST_AUTO_TEST_CASE (client_server_test) image, 0, 24, - 0, 200000000, log ) -- cgit v1.2.3 From 8349f0c97d98c0b7550ff4c76ad25f8f06270d6a Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Mon, 22 Jul 2013 16:23:23 +0100 Subject: Basics of front-end 3D (as far as viewer, at least). --- src/lib/dcp_video_frame.cc | 32 +++++++------ src/lib/dcp_video_frame.h | 11 +++-- src/lib/encoder.cc | 23 ++++----- src/lib/encoder.h | 4 +- src/lib/ffmpeg_decoder.cc | 2 +- src/lib/film.cc | 48 +++++++++++++++++-- src/lib/film.h | 18 +++++-- src/lib/player.cc | 15 +++--- src/lib/player.h | 9 ++-- src/lib/server.cc | 3 +- src/lib/still_image_decoder.cc | 2 +- src/lib/transcoder.cc | 6 +-- src/lib/types.h | 9 ++++ src/lib/video_content.cc | 3 +- src/lib/video_decoder.cc | 17 ++++++- src/lib/video_decoder.h | 10 ++-- src/lib/writer.cc | 103 ++++++++++++++++++++++++++++------------- src/lib/writer.h | 11 +++-- src/wx/audio_mapping_view.cc | 4 -- src/wx/film_editor.cc | 20 ++++++++ src/wx/film_editor.h | 2 + src/wx/film_viewer.cc | 10 ++-- src/wx/film_viewer.h | 2 +- src/wx/video_panel.cc | 5 +- test/client_server_test.cc | 1 + 25 files changed, 266 insertions(+), 104 deletions(-) (limited to 'src/lib/server.cc') diff --git a/src/lib/dcp_video_frame.cc b/src/lib/dcp_video_frame.cc index ef8db7d23..10f1e4ad1 100644 --- a/src/lib/dcp_video_frame.cc +++ b/src/lib/dcp_video_frame.cc @@ -77,10 +77,11 @@ using libdcp::Size; * @param l Log to write to. */ DCPVideoFrame::DCPVideoFrame ( - shared_ptr image, int f, int dcp_fps, int bw, shared_ptr l + shared_ptr image, int f, Eyes eyes, int dcp_fps, int bw, shared_ptr l ) : _image (image) , _frame (f) + , _eyes (eyes) , _frames_per_second (dcp_fps) , _j2k_bandwidth (bw) , _log (l) @@ -102,7 +103,11 @@ DCPVideoFrame::encode_locally () ); /* Set the max image and component sizes based on frame_rate */ - int const max_cs_len = ((float) _j2k_bandwidth) / 8 / _frames_per_second; + int max_cs_len = ((float) _j2k_bandwidth) / 8 / _frames_per_second; + if (_eyes == EYES_LEFT || _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 */ @@ -208,12 +213,13 @@ DCPVideoFrame::encode_remotely (ServerDescription const * serv) socket->connect (*endpoint_iterator); stringstream s; - s << N_("encode please\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") - << N_("j2k_bandwidth ") << _j2k_bandwidth << N_("\n"); + s << "encode please\n" + << "width " << _image->size().width << "\n" + << "height " << _image->size().height << "\n" + << "eyes " << static_cast (_eyes) << "\n" + << "frame " << _frame << "\n" + << "frames_per_second " << _frames_per_second << "\n" + << "j2k_bandwidth " << _j2k_bandwidth << "\n"; _log->log (String::compose ( N_("Sending to remote; pixel format %1, components %2, lines (%3,%4,%5), line sizes (%6,%7,%8)"), @@ -272,9 +278,9 @@ EncodedData::~EncodedData () * @param frame DCP frame index. */ void -EncodedData::write (shared_ptr film, int frame) const +EncodedData::write (shared_ptr film, int frame, Eyes eyes) const { - string const tmp_j2c = film->j2c_path (frame, true); + string const tmp_j2c = film->j2c_path (frame, eyes, true); FILE* f = fopen (tmp_j2c.c_str (), N_("wb")); @@ -285,16 +291,16 @@ EncodedData::write (shared_ptr film, int frame) const fwrite (_data, 1, _size, f); fclose (f); - string const real_j2c = film->j2c_path (frame, false); + string 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, libdcp::FrameInfo fin) const +EncodedData::write_info (shared_ptr film, int frame, Eyes eyes, libdcp::FrameInfo fin) const { - string const info = film->info_path (frame); + string const info = film->info_path (frame, eyes); ofstream h (info.c_str()); fin.write (h); } diff --git a/src/lib/dcp_video_frame.h b/src/lib/dcp_video_frame.h index 4c545b6ef..e786d9b61 100644 --- a/src/lib/dcp_video_frame.h +++ b/src/lib/dcp_video_frame.h @@ -47,8 +47,8 @@ public: virtual ~EncodedData (); void send (boost::shared_ptr socket); - void write (boost::shared_ptr, int) const; - void write_info (boost::shared_ptr, int, libdcp::FrameInfo) const; + void write (boost::shared_ptr, int, Eyes) const; + void write_info (boost::shared_ptr, int, Eyes, libdcp::FrameInfo) const; /** @return data */ uint8_t* data () const { @@ -101,11 +101,15 @@ public: class DCPVideoFrame : public boost::noncopyable { public: - DCPVideoFrame (boost::shared_ptr, int, int, int, boost::shared_ptr); + DCPVideoFrame (boost::shared_ptr, int, Eyes, int, int, boost::shared_ptr); boost::shared_ptr encode_locally (); boost::shared_ptr encode_remotely (ServerDescription const *); + Eyes eyes () const { + return _eyes; + } + int frame () const { return _frame; } @@ -113,6 +117,7 @@ public: private: boost::shared_ptr _image; int _frame; ///< frame index within the DCP's intrinsic duration + Eyes _eyes; int _frames_per_second; ///< Frames per second that we will use for the DCP int _j2k_bandwidth; ///< J2K bandwidth to use diff --git a/src/lib/encoder.cc b/src/lib/encoder.cc index 718ae55a4..8e61a0d60 100644 --- a/src/lib/encoder.cc +++ b/src/lib/encoder.cc @@ -52,10 +52,11 @@ Encoder::Encoder (shared_ptr f, shared_ptr j) : _film (f) , _job (j) , _video_frames_out (0) - , _have_a_real_frame (false) , _terminate (false) { - + _have_a_real_frame[EYES_BOTH] = false; + _have_a_real_frame[EYES_LEFT] = false; + _have_a_real_frame[EYES_RIGHT] = false; } Encoder::~Encoder () @@ -117,7 +118,7 @@ Encoder::process_end () for (list >::iterator i = _queue.begin(); i != _queue.end(); ++i) { _film->log()->log (String::compose (N_("Encode left-over frame %1"), (*i)->frame ())); try { - _writer->write ((*i)->encode_locally(), (*i)->frame ()); + _writer->write ((*i)->encode_locally(), (*i)->frame (), (*i)->eyes ()); frame_done (); } catch (std::exception& e) { _film->log()->log (String::compose (N_("Local encode failed (%1)"), e.what ())); @@ -170,7 +171,7 @@ Encoder::frame_done () } void -Encoder::process_video (shared_ptr image, bool same) +Encoder::process_video (shared_ptr image, Eyes eyes, bool same) { boost::mutex::scoped_lock lock (_mutex); @@ -190,25 +191,25 @@ Encoder::process_video (shared_ptr image, bool same) } if (_writer->can_fake_write (_video_frames_out)) { - _writer->fake_write (_video_frames_out); - _have_a_real_frame = false; + _writer->fake_write (_video_frames_out, eyes); + _have_a_real_frame[eyes] = false; frame_done (); - } else if (same && _have_a_real_frame) { + } else if (same && _have_a_real_frame[eyes]) { /* Use the last frame that we encoded. */ - _writer->repeat (_video_frames_out); + _writer->repeat (_video_frames_out, eyes); frame_done (); } else { /* Queue this new frame for encoding */ TIMING ("adding to queue of %1", _queue.size ()); _queue.push_back (shared_ptr ( new DCPVideoFrame ( - image, _video_frames_out, _film->dcp_video_frame_rate(), + image, _video_frames_out, eyes, _film->dcp_video_frame_rate(), _film->j2k_bandwidth(), _film->log() ) )); _condition.notify_all (); - _have_a_real_frame = true; + _have_a_real_frame[eyes] = true; } ++_video_frames_out; @@ -302,7 +303,7 @@ Encoder::encoder_thread (ServerDescription* server) } if (encoded) { - _writer->write (encoded, vf->frame ()); + _writer->write (encoded, vf->frame (), vf->eyes ()); frame_done (); } else { lock.lock (); diff --git a/src/lib/encoder.h b/src/lib/encoder.h index a6e5932be..a866a77f1 100644 --- a/src/lib/encoder.h +++ b/src/lib/encoder.h @@ -66,7 +66,7 @@ public: * @param i Video frame image. * @param same true if i is the same as the last time we were called. */ - void process_video (boost::shared_ptr i, bool same); + void process_video (boost::shared_ptr i, Eyes eyes, bool same); /** Call with some audio data */ void process_audio (boost::shared_ptr); @@ -100,7 +100,7 @@ private: /** Number of video frames written for the DCP so far */ int _video_frames_out; - bool _have_a_real_frame; + bool _have_a_real_frame[EYES_COUNT]; bool _terminate; std::list > _queue; std::list _threads; diff --git a/src/lib/ffmpeg_decoder.cc b/src/lib/ffmpeg_decoder.cc index 11cea8fb1..ea32d102d 100644 --- a/src/lib/ffmpeg_decoder.cc +++ b/src/lib/ffmpeg_decoder.cc @@ -59,7 +59,7 @@ using libdcp::Size; FFmpegDecoder::FFmpegDecoder (shared_ptr f, shared_ptr c, bool video, bool audio) : Decoder (f) - , VideoDecoder (f) + , VideoDecoder (f, c) , AudioDecoder (f) , SubtitleDecoder (f) , FFmpeg (c) diff --git a/src/lib/film.cc b/src/lib/film.cc index e39e94cfc..40c696256 100644 --- a/src/lib/film.cc +++ b/src/lib/film.cc @@ -95,6 +95,7 @@ Film::Film (string d) , _dci_metadata (Config::instance()->default_dci_metadata ()) , _dcp_video_frame_rate (24) , _dcp_audio_channels (MAX_AUDIO_CHANNELS) + , _dcp_3d (false) , _sequence_video (true) , _dirty (false) { @@ -141,6 +142,10 @@ Film::video_identifier () const << "_" << scaler()->id() << "_" << j2k_bandwidth(); + if (_dcp_3d) { + s << "_3D"; + } + return s.str (); } @@ -327,6 +332,7 @@ Film::write_metadata () const root->add_child("DCPVideoFrameRate")->add_child_text (lexical_cast (_dcp_video_frame_rate)); root->add_child("DCIDate")->add_child_text (boost::gregorian::to_iso_string (_dci_date)); root->add_child("DCPAudioChannels")->add_child_text (lexical_cast (_dcp_audio_channels)); + root->add_child("DCP3D")->add_child_text (_dcp_3d ? "1" : "0"); root->add_child("SequenceVideo")->add_child_text (_sequence_video ? "1" : "0"); _playlist->as_xml (root->add_child ("Playlist")); @@ -439,6 +445,14 @@ Film::dci_name (bool if_created_now) const d << "_" << dcp_content_type()->dci_name(); } + if (dcp_3d ()) { + d << "-3D"; + } + + if (dcp_video_frame_rate() != 24) { + d << "-" << dcp_video_frame_rate(); + } + if (container()) { d << "_" << container()->dci_name(); } @@ -635,6 +649,16 @@ Film::set_dcp_audio_channels (int c) signal_changed (DCP_AUDIO_CHANNELS); } +void +Film::set_dcp_3d (bool t) +{ + { + boost::mutex::scoped_lock lm (_state_mutex); + _dcp_3d = t; + } + signal_changed (DCP_3D); +} + void Film::signal_changed (Property p) { @@ -667,15 +691,23 @@ Film::set_dci_date_today () } string -Film::info_path (int f) const +Film::info_path (int f, Eyes e) const { boost::filesystem::path p; p /= info_dir (); stringstream s; s.width (8); - s << setfill('0') << f << ".md5"; + s << setfill('0') << f; + + if (e == EYES_LEFT) { + s << ".L"; + } else if (e == EYES_RIGHT) { + s << ".R"; + } + s << ".md5"; + p /= s.str(); /* info_dir() will already have added any initial bit of the path, @@ -685,7 +717,7 @@ Film::info_path (int f) const } string -Film::j2c_path (int f, bool t) const +Film::j2c_path (int f, Eyes e, bool t) const { boost::filesystem::path p; p /= "j2c"; @@ -693,7 +725,15 @@ Film::j2c_path (int f, bool t) const stringstream s; s.width (8); - s << setfill('0') << f << ".j2c"; + s << setfill('0') << f; + + if (e == EYES_LEFT) { + s << ".L"; + } else if (e == EYES_RIGHT) { + s << ".R"; + } + + s << ".j2c"; if (t) { s << ".tmp"; diff --git a/src/lib/film.h b/src/lib/film.h index 99c214ab7..5aff6f0be 100644 --- a/src/lib/film.h +++ b/src/lib/film.h @@ -55,8 +55,8 @@ public: Film (std::string d); std::string info_dir () const; - std::string j2c_path (int f, bool t) const; - std::string info_path (int f) const; + std::string j2c_path (int, Eyes, bool) const; + std::string info_path (int, Eyes) const; std::string internal_video_mxf_dir () const; std::string internal_video_mxf_filename () const; boost::filesystem::path audio_analysis_path (boost::shared_ptr) const; @@ -130,7 +130,9 @@ public: DCI_METADATA, DCP_VIDEO_FRAME_RATE, DCP_AUDIO_CHANNELS, - SEQUENCE_VIDEO + /** The setting of _dcp_3d has been changed */ + DCP_3D, + SEQUENCE_VIDEO, }; @@ -197,6 +199,11 @@ public: return _dcp_audio_channels; } + bool dcp_3d () const { + boost::mutex::scoped_lock lm (_state_mutex); + return _dcp_3d; + } + bool sequence_video () const { boost::mutex::scoped_lock lm (_state_mutex); return _sequence_video; @@ -220,6 +227,7 @@ public: void set_dci_metadata (DCIMetadata); void set_dcp_video_frame_rate (int); void set_dcp_audio_channels (int); + void set_dcp_3d (bool); void set_dci_date_today (); void set_sequence_video (bool); @@ -275,6 +283,10 @@ private: /** The date that we should use in a DCI name */ boost::gregorian::date _dci_date; int _dcp_audio_channels; + /** If true, the DCP will be written in 3D mode; otherwise in 2D. + This will be regardless of what content is on the playlist. + */ + bool _dcp_3d; bool _sequence_video; /** true if our state has changed since we last saved it */ diff --git a/src/lib/player.cc b/src/lib/player.cc index 98a31ae74..20beda945 100644 --- a/src/lib/player.cc +++ b/src/lib/player.cc @@ -202,7 +202,7 @@ Player::pass () } void -Player::process_video (weak_ptr weak_piece, shared_ptr image, bool same, VideoContent::Frame frame) +Player::process_video (weak_ptr weak_piece, shared_ptr image, Eyes eyes, bool same, VideoContent::Frame frame) { shared_ptr piece = weak_piece.lock (); if (!piece) { @@ -242,11 +242,11 @@ Player::process_video (weak_ptr weak_piece, shared_ptr image _last_video = piece->content; #endif - Video (work_image, same, time); + Video (work_image, eyes, same, time); time += TIME_HZ / _film->dcp_video_frame_rate(); if (frc.repeat) { - Video (work_image, true, time); + Video (work_image, eyes, true, time); time += TIME_HZ / _film->dcp_video_frame_rate(); } @@ -414,7 +414,7 @@ Player::setup_pieces () if (fc) { shared_ptr fd (new FFmpegDecoder (_film, fc, _video, _audio)); - fd->Video.connect (bind (&Player::process_video, this, piece, _1, _2, _3)); + fd->Video.connect (bind (&Player::process_video, this, piece, _1, _2, _3, _4)); fd->Audio.connect (bind (&Player::process_audio, this, piece, _1, _2)); fd->Subtitle.connect (bind (&Player::process_subtitle, this, piece, _1, _2, _3, _4)); @@ -435,7 +435,7 @@ Player::setup_pieces () if (!id) { id.reset (new StillImageDecoder (_film, ic)); - id->Video.connect (bind (&Player::process_video, this, piece, _1, _2, _3)); + id->Video.connect (bind (&Player::process_video, this, piece, _1, _2, _3, _4)); } piece->decoder = id; @@ -479,6 +479,9 @@ Player::content_changed (weak_ptr w, int property, bool frequent) } else if (property == SubtitleContentProperty::SUBTITLE_OFFSET || property == SubtitleContentProperty::SUBTITLE_SCALE) { update_subtitle (); Changed (frequent); + } else if (property == VideoContentProperty::VIDEO_FRAME_TYPE) { + cout << "vft change.\n"; + Changed (frequent); } } @@ -518,7 +521,7 @@ Player::emit_black () #endif /* XXX: use same here */ - Video (_black_frame, false, _video_position); + Video (_black_frame, EYES_BOTH, false, _video_position); _video_position += _film->video_frames_to_time (1); } diff --git a/src/lib/player.h b/src/lib/player.h index 568c7a7a1..8b28f010d 100644 --- a/src/lib/player.h +++ b/src/lib/player.h @@ -60,10 +60,11 @@ 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 the time. + * Second parameter is the eye(s) that should see this image. + * Third parameter is true if the image is the same as the last one that was emitted. + * Fourth parameter is the time. */ - boost::signals2::signal, bool, Time)> Video; + boost::signals2::signal, Eyes, bool, Time)> Video; /** Emitted when some audio data is ready */ boost::signals2::signal, Time)> Audio; @@ -79,7 +80,7 @@ public: private: friend class PlayerWrapper; - void process_video (boost::weak_ptr, boost::shared_ptr, bool, VideoContent::Frame); + void process_video (boost::weak_ptr, boost::shared_ptr, Eyes, bool, VideoContent::Frame); void process_audio (boost::weak_ptr, boost::shared_ptr, AudioContent::Frame); void process_subtitle (boost::weak_ptr, boost::shared_ptr, dcpomatic::Rect, Time, Time); void setup_pieces (); diff --git a/src/lib/server.cc b/src/lib/server.cc index 9af0883a7..37a076a54 100644 --- a/src/lib/server.cc +++ b/src/lib/server.cc @@ -105,13 +105,14 @@ Server::process (shared_ptr socket) int frame = get_required_int (kv, "frame"); int frames_per_second = get_required_int (kv, "frames_per_second"); int j2k_bandwidth = get_required_int (kv, "j2k_bandwidth"); + Eyes eyes = static_cast (get_required_int (kv, "eyes")); shared_ptr image (new Image (PIX_FMT_RGB24, size, true)); image->read_from_socket (socket); DCPVideoFrame dcp_video_frame ( - image, frame, frames_per_second, j2k_bandwidth, _log + image, frame, eyes, frames_per_second, j2k_bandwidth, _log ); shared_ptr encoded = dcp_video_frame.encode_locally (); diff --git a/src/lib/still_image_decoder.cc b/src/lib/still_image_decoder.cc index 21cc83f54..10e34427b 100644 --- a/src/lib/still_image_decoder.cc +++ b/src/lib/still_image_decoder.cc @@ -34,7 +34,7 @@ using libdcp::Size; StillImageDecoder::StillImageDecoder (shared_ptr f, shared_ptr c) : Decoder (f) - , VideoDecoder (f) + , VideoDecoder (f, c) , StillImage (c) { diff --git a/src/lib/transcoder.cc b/src/lib/transcoder.cc index 7022965bd..3002ef61c 100644 --- a/src/lib/transcoder.cc +++ b/src/lib/transcoder.cc @@ -40,11 +40,11 @@ using boost::weak_ptr; using boost::dynamic_pointer_cast; static void -video_proxy (weak_ptr encoder, shared_ptr image, bool same) +video_proxy (weak_ptr encoder, shared_ptr image, Eyes eyes, bool same) { shared_ptr e = encoder.lock (); if (e) { - e->process_video (image, same); + e->process_video (image, eyes, same); } } @@ -67,7 +67,7 @@ Transcoder::Transcoder (shared_ptr f, shared_ptr j) , _player (f->make_player ()) , _encoder (new Encoder (f, j)) { - _player->Video.connect (bind (video_proxy, _encoder, _1, _2)); + _player->Video.connect (bind (video_proxy, _encoder, _1, _2, _3)); _player->Audio.connect (bind (audio_proxy, _encoder, _1)); } diff --git a/src/lib/types.h b/src/lib/types.h index b1b359810..d6136fc3e 100644 --- a/src/lib/types.h +++ b/src/lib/types.h @@ -40,12 +40,21 @@ enum VideoFrameType VIDEO_FRAME_TYPE_3D_LEFT_RIGHT }; +enum Eyes +{ + EYES_BOTH, + EYES_LEFT, + EYES_RIGHT, + EYES_COUNT +}; + /** @struct Crop * @brief A description of the crop of an image or video. */ struct Crop { Crop () : left (0), right (0), top (0), bottom (0) {} + Crop (int l, int r, int t, int b) : left (l), right (r), top (t), bottom (b) {} /** Number of pixels to remove from the left-hand side */ int left; diff --git a/src/lib/video_content.cc b/src/lib/video_content.cc index 7eca53c3d..076cd6ec6 100644 --- a/src/lib/video_content.cc +++ b/src/lib/video_content.cc @@ -35,6 +35,7 @@ int const VideoContentProperty::VIDEO_RATIO = 4; using std::string; using std::stringstream; using std::setprecision; +using std::cout; using boost::shared_ptr; using boost::lexical_cast; using boost::optional; @@ -231,7 +232,7 @@ VideoContent::set_video_frame_type (VideoFrameType t) { { boost::mutex::scoped_lock lm (_mutex); - _video_frame_rate = t; + _video_frame_type = t; } signal_changed (VideoContentProperty::VIDEO_FRAME_TYPE); diff --git a/src/lib/video_decoder.cc b/src/lib/video_decoder.cc index 38d5dfcb8..eaa4534e4 100644 --- a/src/lib/video_decoder.cc +++ b/src/lib/video_decoder.cc @@ -25,8 +25,9 @@ using std::cout; using boost::shared_ptr; -VideoDecoder::VideoDecoder (shared_ptr f) +VideoDecoder::VideoDecoder (shared_ptr f, shared_ptr c) : Decoder (f) + , _video_content (c) , _video_position (0) { @@ -35,7 +36,19 @@ VideoDecoder::VideoDecoder (shared_ptr f) void VideoDecoder::video (shared_ptr image, bool same, VideoContent::Frame frame) { - Video (image, same, frame); + switch (_video_content->video_frame_type ()) { + case VIDEO_FRAME_TYPE_2D: + Video (image, EYES_BOTH, same, frame); + break; + case VIDEO_FRAME_TYPE_3D_LEFT_RIGHT: + { + int const half = image->size().width / 2; + Video (image->crop (Crop (0, half, 0, 0), true), EYES_LEFT, same, frame); + Video (image->crop (Crop (half, 0, 0, 0), true), EYES_RIGHT, same, frame); + break; + } + } + _video_position = frame + 1; } diff --git a/src/lib/video_decoder.h b/src/lib/video_decoder.h index 26a11c805..142320a04 100644 --- a/src/lib/video_decoder.h +++ b/src/lib/video_decoder.h @@ -32,7 +32,7 @@ class Image; class VideoDecoder : public virtual Decoder { public: - VideoDecoder (boost::shared_ptr); + VideoDecoder (boost::shared_ptr, boost::shared_ptr); /** Seek so that the next pass() will yield (approximately) the requested frame. * Pass accurate = true to try harder to get close to the request. @@ -41,14 +41,16 @@ 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 the frame within our source. + * Second parameter is the eye(s) which should see this image. + * Third parameter is true if the image is the same as the last one that was emitted for this Eyes value. + * Fourth parameter is the frame within our source. */ - boost::signals2::signal, bool, VideoContent::Frame)> Video; + boost::signals2::signal, Eyes, bool, VideoContent::Frame)> Video; protected: void video (boost::shared_ptr, bool, VideoContent::Frame); + boost::shared_ptr _video_content; VideoContent::Frame _video_position; }; diff --git a/src/lib/writer.cc b/src/lib/writer.cc index c5360a122..122dcd716 100644 --- a/src/lib/writer.cc +++ b/src/lib/writer.cc @@ -99,7 +99,7 @@ Writer::Writer (shared_ptr f, shared_ptr j) } void -Writer::write (shared_ptr encoded, int frame) +Writer::write (shared_ptr encoded, int frame, Eyes eyes) { boost::mutex::scoped_lock lock (_mutex); @@ -107,6 +107,7 @@ Writer::write (shared_ptr encoded, int frame) qi.type = QueueItem::FULL; qi.encoded = encoded; qi.frame = frame; + qi.eyes = eyes; _queue.push_back (qi); ++_queued_full_in_memory; @@ -114,17 +115,18 @@ Writer::write (shared_ptr encoded, int frame) } void -Writer::fake_write (int frame) +Writer::fake_write (int frame, Eyes eyes) { boost::mutex::scoped_lock lock (_mutex); - ifstream ifi (_film->info_path (frame).c_str()); + ifstream ifi (_film->info_path (frame, eyes).c_str()); libdcp::FrameInfo info (ifi); QueueItem qi; qi.type = QueueItem::FAKE; qi.size = info.size; qi.frame = frame; + qi.eyes = eyes; _queue.push_back (qi); _condition.notify_all (); @@ -137,6 +139,23 @@ Writer::write (shared_ptr audio) _sound_asset_writer->write (audio->data(), audio->frames()); } +/** This must be called from Writer::thread() with an appropriate lock held */ +bool +Writer::have_sequenced_image_at_queue_head () const +{ + if (_queue.empty ()) { + return false; + } + + /* We assume that we will get either all 2D frames or all 3D frames, not a mixture */ + + bool const eyes_ok = (_queue.front().eyes == EYES_BOTH) || + (_queue.front().eyes == EYES_LEFT && _last_written_eyes == EYES_RIGHT) || + (_queue.front().eyes == EYES_RIGHT && _last_written_eyes == EYES_LEFT); + + return _queue.front().frame == (_last_written_frame + 1) && eyes_ok; +} + void Writer::thread () try @@ -149,10 +168,7 @@ try _queue.sort (); - if (_finish || - _queued_full_in_memory > _maximum_frames_in_memory || - (!_queue.empty() && _queue.front().frame == (_last_written_frame + 1))) { - + if (_finish || _queued_full_in_memory > _maximum_frames_in_memory || have_sequenced_image_at_queue_head ()) { break; } @@ -166,7 +182,7 @@ try } /* Write any frames that we can write; i.e. those that are in sequence */ - while (!_queue.empty() && _queue.front().frame == (_last_written_frame + 1)) { + while (have_sequenced_image_at_queue_head ()) { QueueItem qi = _queue.front (); _queue.pop_front (); if (qi.type == QueueItem::FULL && qi.encoded) { @@ -179,10 +195,10 @@ try { _film->log()->log (String::compose (N_("Writer FULL-writes %1 to MXF"), qi.frame)); if (!qi.encoded) { - qi.encoded.reset (new EncodedData (_film->j2c_path (qi.frame, false))); + qi.encoded.reset (new EncodedData (_film->j2c_path (qi.frame, qi.eyes, false))); } libdcp::FrameInfo const fin = _picture_asset_writer->write (qi.encoded->data(), qi.encoded->size()); - qi.encoded->write_info (_film, qi.frame, fin); + qi.encoded->write_info (_film, qi.frame, qi.eyes, fin); _last_written = qi.encoded; ++_full_written; break; @@ -197,7 +213,7 @@ try { _film->log()->log (String::compose (N_("Writer REPEAT-writes %1 to MXF"), qi.frame)); libdcp::FrameInfo const fin = _picture_asset_writer->write (_last_written->data(), _last_written->size()); - _last_written->write_info (_film, qi.frame, fin); + _last_written->write_info (_film, qi.frame, qi.eyes, fin); ++_repeat_written; break; } @@ -231,7 +247,7 @@ try lock.unlock (); _film->log()->log (String::compose (N_("Writer full (awaiting %1); pushes %2 to disk"), _last_written_frame + 1, qi.frame)); - qi.encoded->write (_film, qi.frame); + qi.encoded->write (_film, qi.frame, qi.eyes); lock.lock (); qi.encoded.reset (); --_queued_full_in_memory; @@ -324,19 +340,44 @@ Writer::finish () /** Tell the writer that frame `f' should be a repeat of the frame before it */ void -Writer::repeat (int f) +Writer::repeat (int f, Eyes e) { boost::mutex::scoped_lock lock (_mutex); QueueItem qi; qi.type = QueueItem::REPEAT; qi.frame = f; + qi.eyes = e; _queue.push_back (qi); _condition.notify_all (); } +bool +Writer::check_existing_picture_mxf_frame (FILE* mxf, int f, Eyes eyes) +{ + /* Read the frame info as written */ + ifstream ifi (_film->info_path (f, eyes).c_str()); + libdcp::FrameInfo info (ifi); + + /* Read the data from the MXF and hash it */ + fseek (mxf, info.offset, SEEK_SET); + EncodedData data (info.size); + size_t const read = fread (data.data(), 1, data.size(), mxf); + if (read != static_cast (data.size ())) { + _film->log()->log (String::compose ("Existing frame %1 is incomplete", f)); + return false; + } + + string const existing_hash = md5_digest (data.data(), data.size()); + if (existing_hash != info.hash) { + _film->log()->log (String::compose ("Existing frame %1 failed hash check", f)); + return false; + } + + return true; +} void Writer::check_existing_picture_mxf () @@ -353,23 +394,17 @@ Writer::check_existing_picture_mxf () while (1) { - /* Read the frame info as written */ - ifstream ifi (_film->info_path (_first_nonexistant_frame).c_str()); - libdcp::FrameInfo info (ifi); - - /* Read the data from the MXF and hash it */ - fseek (mxf, info.offset, SEEK_SET); - EncodedData data (info.size); - size_t const read = fread (data.data(), 1, data.size(), mxf); - if (read != static_cast (data.size ())) { - _film->log()->log (String::compose ("Existing frame %1 is incomplete", _first_nonexistant_frame)); - break; - } - - string const existing_hash = md5_digest (data.data(), data.size()); - if (existing_hash != info.hash) { - _film->log()->log (String::compose ("Existing frame %1 failed hash check", _first_nonexistant_frame)); - break; + if (_film->dcp_3d ()) { + if (!check_existing_picture_mxf_frame (mxf, _first_nonexistant_frame, EYES_LEFT)) { + break; + } + if (!check_existing_picture_mxf_frame (mxf, _first_nonexistant_frame, EYES_RIGHT)) { + break; + } + } else { + if (!check_existing_picture_mxf_frame (mxf, _first_nonexistant_frame, EYES_BOTH)) { + break; + } } _film->log()->log (String::compose ("Have existing frame %1", _first_nonexistant_frame)); @@ -394,11 +429,15 @@ Writer::can_fake_write (int frame) const bool operator< (QueueItem const & a, QueueItem const & b) { - return a.frame < b.frame; + if (a.frame != b.frame) { + return a.frame < b.frame; + } + + return a.eyes == EYES_LEFT && b.eyes == EYES_RIGHT; } bool operator== (QueueItem const & a, QueueItem const & b) { - return a.frame == b.frame; + return a.frame == b.frame && a.eyes == b.eyes; } diff --git a/src/lib/writer.h b/src/lib/writer.h index 1e5d86489..023107d97 100644 --- a/src/lib/writer.h +++ b/src/lib/writer.h @@ -22,6 +22,7 @@ #include #include #include "exceptions.h" +#include "types.h" class Film; class EncodedData; @@ -56,6 +57,7 @@ public: int size; /** frame index */ int frame; + Eyes eyes; }; bool operator< (QueueItem const & a, QueueItem const & b); @@ -68,16 +70,18 @@ public: bool can_fake_write (int) const; - void write (boost::shared_ptr, int); - void fake_write (int); + void write (boost::shared_ptr, int, Eyes); + void fake_write (int, Eyes); void write (boost::shared_ptr); - void repeat (int f); + void repeat (int f, Eyes); void finish (); private: void thread (); void check_existing_picture_mxf (); + bool check_existing_picture_mxf_frame (FILE *, int, Eyes); + bool have_sequenced_image_at_queue_head () const; /** our Film */ boost::shared_ptr _film; @@ -101,6 +105,7 @@ private: boost::shared_ptr _last_written; /** the index of the last written frame */ int _last_written_frame; + Eyes _last_written_eyes; /** maximum number of frames to hold in memory, for when we are managing ordering */ diff --git a/src/wx/audio_mapping_view.cc b/src/wx/audio_mapping_view.cc index 45d11cf80..f5d0ecae2 100644 --- a/src/wx/audio_mapping_view.cc +++ b/src/wx/audio_mapping_view.cc @@ -109,15 +109,12 @@ AudioMappingView::left_click (wxGridEvent& ev) } if (_grid->GetCellValue (ev.GetRow(), ev.GetCol()) == wxT("1")) { - cout << "set " << ev.GetRow() << " " << ev.GetCol() << " to 0.\n"; _grid->SetCellValue (ev.GetRow(), ev.GetCol(), wxT("0")); } else { - cout << "set " << ev.GetRow() << " " << ev.GetCol() << " to 1.\n"; _grid->SetCellValue (ev.GetRow(), ev.GetCol(), wxT("1")); } _map = AudioMapping (_map.content_channels ()); - cout << "was: " << _map.dcp_to_content(libdcp::CENTRE).size() << "\n"; for (int i = 0; i < _grid->GetNumberRows(); ++i) { for (int j = 1; j < _grid->GetNumberCols(); ++j) { @@ -127,7 +124,6 @@ AudioMappingView::left_click (wxGridEvent& ev) } } - cout << "changed: " << _map.dcp_to_content(libdcp::CENTRE).size() << "\n"; Changed (_map); } diff --git a/src/wx/film_editor.cc b/src/wx/film_editor.cc index 39935927f..048791a10 100644 --- a/src/wx/film_editor.cc +++ b/src/wx/film_editor.cc @@ -151,6 +151,10 @@ FilmEditor::make_dcp_panel () grid->Add (_dcp_audio_channels, wxGBPosition (r, 1)); ++r; + _dcp_3d = new wxCheckBox (_dcp_panel, wxID_ANY, _("3D")); + grid->Add (_dcp_3d, wxGBPosition (r, 0), wxGBSpan (1, 2)); + ++r; + add_label_to_grid_bag_sizer (grid, _dcp_panel, _("Resolution"), true, wxGBPosition (r, 0)); _dcp_resolution = new wxChoice (_dcp_panel, wxID_ANY); grid->Add (_dcp_resolution, wxGBPosition (r, 1)); @@ -219,6 +223,7 @@ FilmEditor::connect_to_widgets () _j2k_bandwidth->Connect (wxID_ANY, wxEVT_COMMAND_SPINCTRL_UPDATED, wxCommandEventHandler (FilmEditor::j2k_bandwidth_changed), 0, this); _dcp_resolution->Connect (wxID_ANY, wxEVT_COMMAND_CHOICE_SELECTED, wxCommandEventHandler (FilmEditor::dcp_resolution_changed), 0, this); _sequence_video->Connect (wxID_ANY, wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler (FilmEditor::sequence_video_changed), 0, this); + _dcp_3d->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&FilmEditor::dcp_3d_changed, this)); } void @@ -403,6 +408,9 @@ FilmEditor::film_changed (Film::Property p) case Film::SEQUENCE_VIDEO: checked_set (_sequence_video, _film->sequence_video ()); break; + case Film::DCP_3D: + checked_set (_dcp_3d, _film->dcp_3d ()); + break; } } @@ -521,6 +529,7 @@ FilmEditor::set_film (shared_ptr f) film_changed (Film::DCP_VIDEO_FRAME_RATE); film_changed (Film::DCP_AUDIO_CHANNELS); film_changed (Film::SEQUENCE_VIDEO); + film_changed (Film::DCP_3D); if (!_film->content().empty ()) { set_selection (_film->content().front ()); @@ -549,6 +558,7 @@ FilmEditor::set_general_sensitivity (bool s) _sequence_video->Enable (s); _dcp_resolution->Enable (s); _scaler->Enable (s); + _dcp_3d->Enable (s); /* Set the panels in the content notebook */ for (list::iterator i = _panels.begin(); i != _panels.end(); ++i) { @@ -824,3 +834,13 @@ FilmEditor::content_right_click (wxListEvent& ev) cl.push_back (selected_content ()); _menu.popup (cl, ev.GetPoint ()); } + +void +FilmEditor::dcp_3d_changed () +{ + if (!_film) { + return; + } + + _film->set_dcp_3d (_dcp_3d->GetValue ()); +} diff --git a/src/wx/film_editor.h b/src/wx/film_editor.h index 66913643e..9a9ba2906 100644 --- a/src/wx/film_editor.h +++ b/src/wx/film_editor.h @@ -89,6 +89,7 @@ private: void dcp_resolution_changed (wxCommandEvent &); void sequence_video_changed (wxCommandEvent &); void content_right_click (wxListEvent &); + void dcp_3d_changed (); /* Handle changes to the model */ void film_changed (Film::Property); @@ -135,6 +136,7 @@ private: wxChoice* _dcp_frame_rate; wxSpinCtrl* _dcp_audio_channels; wxButton* _best_dcp_frame_rate; + wxCheckBox* _dcp_3d; wxChoice* _dcp_resolution; ContentMenu _menu; diff --git a/src/wx/film_viewer.cc b/src/wx/film_viewer.cc index 42654bde5..b9d554c68 100644 --- a/src/wx/film_viewer.cc +++ b/src/wx/film_viewer.cc @@ -131,7 +131,7 @@ FilmViewer::set_film (shared_ptr f) _player = f->make_player (); _player->disable_audio (); - _player->Video.connect (boost::bind (&FilmViewer::process_video, this, _1, _3)); + _player->Video.connect (boost::bind (&FilmViewer::process_video, this, _1, _2, _4)); _player->Changed.connect (boost::bind (&FilmViewer::player_changed, this, _1)); calculate_sizes (); @@ -280,8 +280,12 @@ FilmViewer::check_play_state () } void -FilmViewer::process_video (shared_ptr image, Time t) +FilmViewer::process_video (shared_ptr image, Eyes eyes, Time t) { + if (eyes == EYES_RIGHT) { + return; + } + if (_got_frame) { /* This is an additional frame emitted by a single pass. Store it. */ _queue.push_front (make_pair (image, t)); @@ -332,7 +336,7 @@ FilmViewer::fetch_next_frame () _got_frame = false; if (!_queue.empty ()) { - process_video (_queue.back().first, _queue.back().second); + process_video (_queue.back().first, EYES_BOTH, _queue.back().second); _queue.pop_back (); } else { try { diff --git a/src/wx/film_viewer.h b/src/wx/film_viewer.h index b45e53d31..af58b5467 100644 --- a/src/wx/film_viewer.h +++ b/src/wx/film_viewer.h @@ -58,7 +58,7 @@ private: void slider_moved (wxScrollEvent &); void play_clicked (wxCommandEvent &); void timer (wxTimerEvent &); - void process_video (boost::shared_ptr, Time); + void process_video (boost::shared_ptr, Eyes, Time); void calculate_sizes (); void check_play_state (); void fetch_current_frame_again (); diff --git a/src/wx/video_panel.cc b/src/wx/video_panel.cc index e08edfa5a..ce0c869ff 100644 --- a/src/wx/video_panel.cc +++ b/src/wx/video_panel.cc @@ -28,6 +28,7 @@ using std::vector; using std::string; using std::pair; +using std::cout; using boost::shared_ptr; using boost::dynamic_pointer_cast; using boost::bind; @@ -103,7 +104,7 @@ VideoPanel::VideoPanel (FilmEditor* e) _frame_type->Append (_("2D")); _frame_type->Append (_("3D left/right")); - _frame_type->Bind (wxEVT_COMMAND_SPINCTRL_UPDATED, bind (&VideoPanel::frame_type_changed, this)); + _frame_type->Bind (wxEVT_COMMAND_CHOICE_SELECTED, bind (&VideoPanel::frame_type_changed, this)); _left_crop->Connect (wxID_ANY, wxEVT_COMMAND_SPINCTRL_UPDATED, wxCommandEventHandler (VideoPanel::left_crop_changed), 0, this); _right_crop->Connect (wxID_ANY, wxEVT_COMMAND_SPINCTRL_UPDATED, wxCommandEventHandler (VideoPanel::right_crop_changed), 0, this); _top_crop->Connect (wxID_ANY, wxEVT_COMMAND_SPINCTRL_UPDATED, wxCommandEventHandler (VideoPanel::top_crop_changed), 0, this); @@ -180,7 +181,7 @@ VideoPanel::film_content_changed (shared_ptr c, int property) shared_ptr fc = dynamic_pointer_cast (c); if (property == VideoContentProperty::VIDEO_FRAME_TYPE) { - checked_set (_frame_type, vc->video_frame_type ()); + checked_set (_frame_type, vc ? vc->video_frame_type () : VIDEO_FRAME_TYPE_2D); } else if (property == VideoContentProperty::VIDEO_CROP) { checked_set (_left_crop, vc ? vc->crop().left : 0); checked_set (_right_crop, vc ? vc->crop().right : 0); diff --git a/test/client_server_test.cc b/test/client_server_test.cc index 7b5b2b7ef..2dc1545d6 100644 --- a/test/client_server_test.cc +++ b/test/client_server_test.cc @@ -75,6 +75,7 @@ BOOST_AUTO_TEST_CASE (client_server_test) new DCPVideoFrame ( image, 0, + EYES_BOTH, 24, 200000000, log -- cgit v1.2.3 From 74a8d26a8907c6e00e29f054178a3425f44e38ed Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Fri, 16 Aug 2013 20:14:33 +0100 Subject: Very basics of colour conversion configuration. --- src/lib/colour_conversion.cc | 101 ++++++++++++++++++++++ src/lib/colour_conversion.h | 45 ++++++++++ src/lib/config.cc | 24 +++++- src/lib/config.h | 16 +++- src/lib/dcp_video_frame.cc | 2 +- src/lib/dcp_video_frame.h | 2 +- src/lib/encoder.cc | 8 +- src/lib/encoder.h | 2 +- src/lib/server.cc | 6 +- src/lib/server.h | 7 +- src/lib/wscript | 1 + src/tools/dcpomatic_cli.cc | 2 +- src/wx/colour_conversion_dialog.cc | 150 +++++++++++++++++++++++++++++++++ src/wx/colour_conversion_dialog.h | 39 +++++++++ src/wx/config_dialog.cc | 167 ++++++++++++------------------------- src/wx/config_dialog.h | 18 ++-- src/wx/editable_list.h | 156 ++++++++++++++++++++++++++++++++++ src/wx/server_dialog.cc | 8 +- src/wx/server_dialog.h | 6 +- src/wx/video_panel.cc | 40 +++++++-- src/wx/video_panel.h | 3 + src/wx/wscript | 1 + test/client_server_test.cc | 6 +- test/test.cc | 2 +- 24 files changed, 651 insertions(+), 161 deletions(-) create mode 100644 src/lib/colour_conversion.cc create mode 100644 src/lib/colour_conversion.h create mode 100644 src/wx/colour_conversion_dialog.cc create mode 100644 src/wx/colour_conversion_dialog.h create mode 100644 src/wx/editable_list.h (limited to 'src/lib/server.cc') diff --git a/src/lib/colour_conversion.cc b/src/lib/colour_conversion.cc new file mode 100644 index 000000000..96dc0e2c9 --- /dev/null +++ b/src/lib/colour_conversion.cc @@ -0,0 +1,101 @@ +/* + 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 +#include +#include "colour_conversion.h" + +#include "i18n.h" + +using std::list; +using std::string; +using boost::shared_ptr; +using boost::lexical_cast; + +ColourConversion::ColourConversion () + : name (_("Untitled")) + , input_gamma (2.4) + , input_gamma_linearised (true) + , matrix (3, 3) + , output_gamma (2.6) +{ + for (int i = 0; i < 3; ++i) { + for (int j = 0; j < 3; ++j) { + matrix (i, j) = libdcp::colour_matrix::xyz_to_rgb[i][j]; + } + } +} + +ColourConversion::ColourConversion (string n, float i, bool il, float const m[3][3], float o) + : name (n) + , input_gamma (i) + , input_gamma_linearised (il) + , matrix (3, 3) + , output_gamma (o) +{ + for (int i = 0; i < 3; ++i) { + for (int j = 0; j < 3; ++j) { + matrix (i, j) = m[i][j]; + } + } +} + +ColourConversion::ColourConversion (shared_ptr node) + : matrix (3, 3) +{ + name = node->string_child ("Name"); + input_gamma = node->number_child ("InputGamma"); + input_gamma_linearised = node->bool_child ("InputGammaLinearised"); + + for (int i = 0; i < 3; ++i) { + for (int j = 0; j < 3; ++j) { + matrix (i, j) = 0; + } + } + + list > m = node->node_children ("Matrix"); + for (list >::iterator i = m.begin(); i != m.end(); ++i) { + int const ti = (*i)->number_attribute ("i"); + int const tj = (*i)->number_attribute ("j"); + matrix(ti, tj) = lexical_cast ((*i)->content ()); + } + + output_gamma = node->number_child ("OutputGamma"); +} + +void +ColourConversion::as_xml (xmlpp::Node* node) const +{ + node->add_child("Name")->add_child_text (name); + node->add_child("InputGamma")->add_child_text (lexical_cast (input_gamma)); + node->add_child("InputGammaLinearised")->add_child_text (input_gamma_linearised ? "1" : "0"); + + for (int i = 0; i < 3; ++i) { + for (int j = 0; j < 3; ++j) { + xmlpp::Element* m = node->add_child("Matrix"); + m->set_attribute ("i", lexical_cast (i)); + m->set_attribute ("j", lexical_cast (j)); + m->add_child_text (lexical_cast (matrix (i, j))); + } + } + + node->add_child("OutputGamma")->add_child_text (lexical_cast (output_gamma)); +} diff --git a/src/lib/colour_conversion.h b/src/lib/colour_conversion.h new file mode 100644 index 000000000..ed89f8c63 --- /dev/null +++ b/src/lib/colour_conversion.h @@ -0,0 +1,45 @@ +/* + 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 + +namespace cxml { + class Node; +} + +namespace xmlpp { + class Node; +} + +class ColourConversion : public boost::noncopyable +{ +public: + ColourConversion (); + ColourConversion (std::string, float, bool, float const matrix[3][3], float); + ColourConversion (boost::shared_ptr); + + void as_xml (xmlpp::Node *) const; + + std::string name; + float input_gamma; + bool input_gamma_linearised; + boost::numeric::ublas::matrix matrix; + float output_gamma; +}; diff --git a/src/lib/config.cc b/src/lib/config.cc index 29b63b5c8..8f4e5aed0 100644 --- a/src/lib/config.cc +++ b/src/lib/config.cc @@ -22,6 +22,7 @@ #include #include #include +#include #include #include "config.h" #include "server.h" @@ -30,6 +31,7 @@ #include "ratio.h" #include "dcp_content_type.h" #include "sound_processor.h" +#include "colour_conversion.h" #include "i18n.h" @@ -62,6 +64,8 @@ Config::Config () _allowed_dcp_frame_rates.push_back (48); _allowed_dcp_frame_rates.push_back (50); _allowed_dcp_frame_rates.push_back (60); + + _colour_conversions.push_back (shared_ptr (new ColourConversion (_("sRGB"), 2.4, true, libdcp::colour_matrix::xyz_to_rgb, 2.6))); } void @@ -81,7 +85,7 @@ Config::read () list > servers = f.node_children ("Server"); for (list >::iterator i = servers.begin(); i != servers.end(); ++i) { - _servers.push_back (new ServerDescription (*i)); + _servers.push_back (shared_ptr (new ServerDescription (*i))); } _tms_ip = f.string_child ("TMSIP"); @@ -111,7 +115,17 @@ Config::read () _default_dci_metadata = DCIMetadata (f.node_child ("DCIMetadata")); _default_still_length = f.optional_number_child("DefaultStillLength").get_value_or (10); - _default_j2k_bandwidth = f.optional_number_child("DefaultJ2KBandwidth").get_value_or (200000000); + _default_j2k_bandwidth = f.optional_number_child("DefaultJ2KBandwidth").get_value_or (200000000); + + list > cc = f.node_children ("ColourConversion"); + + if (!cc.empty ()) { + _colour_conversions.clear (); + } + + for (list >::iterator i = cc.begin(); i != cc.end(); ++i) { + _colour_conversions.push_back (shared_ptr (new ColourConversion (*i))); + } } void @@ -217,7 +231,7 @@ Config::write () const root->add_child("DefaultDirectory")->add_child_text (_default_directory); root->add_child("ServerPort")->add_child_text (lexical_cast (_server_port)); - for (vector::const_iterator i = _servers.begin(); i != _servers.end(); ++i) { + for (vector >::const_iterator i = _servers.begin(); i != _servers.end(); ++i) { (*i)->as_xml (root->add_child ("Server")); } @@ -245,6 +259,10 @@ Config::write () const root->add_child("DefaultStillLength")->add_child_text (lexical_cast (_default_still_length)); root->add_child("DefaultJ2KBandwidth")->add_child_text (lexical_cast (_default_j2k_bandwidth)); + for (vector >::const_iterator i = _colour_conversions.begin(); i != _colour_conversions.end(); ++i) { + (*i)->as_xml (root->add_child ("ColourConversion")); + } + doc.write_to_file_formatted (file (false)); } diff --git a/src/lib/config.h b/src/lib/config.h index 77287e686..40d06a172 100644 --- a/src/lib/config.h +++ b/src/lib/config.h @@ -36,6 +36,7 @@ class Filter; class SoundProcessor; class DCPContentType; class Ratio; +class ColourConversion; /** @class Config * @brief A singleton class holding configuration. @@ -61,7 +62,7 @@ public: } /** @return J2K encoding servers to use */ - std::vector servers () const { + std::vector > servers () const { return _servers; } @@ -122,6 +123,10 @@ public: return _default_j2k_bandwidth; } + std::vector > colour_conversions () const { + return _colour_conversions; + } + /** @param n New number of local encoding threads */ void set_num_local_encoding_threads (int n) { _num_local_encoding_threads = n; @@ -137,7 +142,7 @@ public: } /** @param s New list of servers */ - void set_servers (std::vector s) { + void set_servers (std::vector > s) { _servers = s; } @@ -204,6 +209,10 @@ public: void set_default_j2k_bandwidth (int b) { _default_j2k_bandwidth = b; } + + void set_colour_conversions (std::vector > const & c) { + _colour_conversions = c; + } void write () const; @@ -224,7 +233,7 @@ private: int _server_port; /** J2K encoding servers to use */ - std::vector _servers; + std::vector > _servers; /** Scaler to use for the "A" part of A/B comparisons */ Scaler const * _reference_scaler; /** Filters to use for the "A" part of A/B comparisons */ @@ -248,6 +257,7 @@ private: DCPContentType const * _default_dcp_content_type; libdcp::XMLMetadata _dcp_metadata; int _default_j2k_bandwidth; + std::vector > _colour_conversions; /** Singleton instance, or 0 */ static Config* _instance; diff --git a/src/lib/dcp_video_frame.cc b/src/lib/dcp_video_frame.cc index 4f6ff9987..53cf1753a 100644 --- a/src/lib/dcp_video_frame.cc +++ b/src/lib/dcp_video_frame.cc @@ -213,7 +213,7 @@ DCPVideoFrame::encode_locally () * @return Encoded data. */ shared_ptr -DCPVideoFrame::encode_remotely (ServerDescription const * serv) +DCPVideoFrame::encode_remotely (boost::shared_ptr serv) { boost::asio::io_service io_service; boost::asio::ip::tcp::resolver resolver (io_service); diff --git a/src/lib/dcp_video_frame.h b/src/lib/dcp_video_frame.h index 96a773a6f..18c8fe628 100644 --- a/src/lib/dcp_video_frame.h +++ b/src/lib/dcp_video_frame.h @@ -105,7 +105,7 @@ public: DCPVideoFrame (boost::shared_ptr, int, Eyes, int, int, boost::shared_ptr); boost::shared_ptr encode_locally (); - boost::shared_ptr encode_remotely (ServerDescription const *); + boost::shared_ptr encode_remotely (boost::shared_ptr); Eyes eyes () const { return _eyes; diff --git a/src/lib/encoder.cc b/src/lib/encoder.cc index 0c7434220..a1c024799 100644 --- a/src/lib/encoder.cc +++ b/src/lib/encoder.cc @@ -71,12 +71,12 @@ void Encoder::process_begin () { for (int i = 0; i < Config::instance()->num_local_encoding_threads (); ++i) { - _threads.push_back (new boost::thread (boost::bind (&Encoder::encoder_thread, this, (ServerDescription *) 0))); + _threads.push_back (new boost::thread (boost::bind (&Encoder::encoder_thread, this, shared_ptr ()))); } - vector servers = Config::instance()->servers (); + vector > servers = Config::instance()->servers (); - for (vector::iterator i = servers.begin(); i != servers.end(); ++i) { + for (vector >::iterator i = servers.begin(); i != servers.end(); ++i) { for (int j = 0; j < (*i)->threads (); ++j) { _threads.push_back (new boost::thread (boost::bind (&Encoder::encoder_thread, this, *i))); } @@ -244,7 +244,7 @@ Encoder::terminate_threads () } void -Encoder::encoder_thread (ServerDescription* server) +Encoder::encoder_thread (shared_ptr server) { /* Number of seconds that we currently wait between attempts to connect to the server; not relevant for localhost diff --git a/src/lib/encoder.h b/src/lib/encoder.h index a866a77f1..a4df202a2 100644 --- a/src/lib/encoder.h +++ b/src/lib/encoder.h @@ -81,7 +81,7 @@ private: void frame_done (); - void encoder_thread (ServerDescription *); + void encoder_thread (boost::shared_ptr); void terminate_threads (); /** Film that we are encoding */ diff --git a/src/lib/server.cc b/src/lib/server.cc index 37a076a54..54cffc077 100644 --- a/src/lib/server.cc +++ b/src/lib/server.cc @@ -68,17 +68,17 @@ ServerDescription::as_xml (xmlpp::Node* root) const * @param v Metadata. * @return ServerDescription, or 0. */ -ServerDescription * +shared_ptr ServerDescription::create_from_metadata (string v) { vector b; split (b, v, is_any_of (N_(" "))); if (b.size() != 2) { - return 0; + return shared_ptr (); } - return new ServerDescription (b[0], atoi (b[1].c_str ())); + return shared_ptr (new ServerDescription (b[0], atoi (b[1].c_str ()))); } Server::Server (shared_ptr log) diff --git a/src/lib/server.h b/src/lib/server.h index e6d374369..6307c1867 100644 --- a/src/lib/server.h +++ b/src/lib/server.h @@ -41,6 +41,11 @@ namespace cxml { class ServerDescription { public: + ServerDescription () + : _host_name ("") + , _threads (1) + {} + /** @param h Server host name or IP address in string form. * @param t Number of threads to use on the server. */ @@ -73,7 +78,7 @@ public: void as_xml (xmlpp::Node *) const; - static ServerDescription * create_from_metadata (std::string v); + static boost::shared_ptr create_from_metadata (std::string v); private: /** server's host name */ diff --git a/src/lib/wscript b/src/lib/wscript index 04dae7587..6c45d8b1e 100644 --- a/src/lib/wscript +++ b/src/lib/wscript @@ -8,6 +8,7 @@ sources = """ audio_content.cc audio_decoder.cc audio_mapping.cc + colour_conversion.cc config.cc content.cc content_factory.cc diff --git a/src/tools/dcpomatic_cli.cc b/src/tools/dcpomatic_cli.cc index 7c5852fcc..ff7ab6ffe 100644 --- a/src/tools/dcpomatic_cli.cc +++ b/src/tools/dcpomatic_cli.cc @@ -116,7 +116,7 @@ main (int argc, char* argv[]) dcpomatic_setup (); if (no_remote) { - Config::instance()->set_servers (vector ()); + Config::instance()->set_servers (vector > ()); } cout << "DCP-o-matic " << dcpomatic_version << " git " << dcpomatic_git_commit; diff --git a/src/wx/colour_conversion_dialog.cc b/src/wx/colour_conversion_dialog.cc new file mode 100644 index 000000000..976d295d5 --- /dev/null +++ b/src/wx/colour_conversion_dialog.cc @@ -0,0 +1,150 @@ +/* + 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 +#include "lib/colour_conversion.h" +#include "wx_util.h" +#include "colour_conversion_dialog.h" + +using std::string; +using std::cout; +using boost::shared_ptr; +using boost::lexical_cast; + +ColourConversionDialog::ColourConversionDialog (wxWindow* parent, shared_ptr conversion) + : wxDialog (parent, wxID_ANY, _("Colour conversion")) + , _conversion (conversion) +{ + wxBoxSizer* overall_sizer = new wxBoxSizer (wxVERTICAL); + SetSizer (overall_sizer); + + wxGridBagSizer* table = new wxGridBagSizer (DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP); + overall_sizer->Add (table, 1, wxEXPAND | wxALL, DCPOMATIC_DIALOG_BORDER); + + int r = 0; + + add_label_to_grid_bag_sizer (table, this, _("Name"), true, wxGBPosition (r, 0)); + _name = new wxTextCtrl (this, wxID_ANY, wxT ("")); + table->Add (_name, wxGBPosition (r, 1)); + ++r; + + add_label_to_grid_bag_sizer (table, this, _("Input gamma"), true, wxGBPosition (r, 0)); + _input_gamma = new wxSpinCtrlDouble (this); + table->Add (_input_gamma, wxGBPosition (r, 1)); + ++r; + + _input_gamma_linearised = new wxCheckBox (this, wxID_ANY, _("Linearise input gamma curve for low values")); + table->Add (_input_gamma_linearised, wxGBPosition (r, 0), wxGBSpan (1, 2)); + ++r; + + wxClientDC dc (parent); + wxSize size = dc.GetTextExtent (wxT ("0.123456789012")); + size.SetHeight (-1); + + wxTextValidator validator (wxFILTER_INCLUDE_CHAR_LIST); + wxArrayString list; + + wxString n (wxT ("0123456789.-")); + for (size_t i = 0; i < n.Length(); ++i) { + list.Add (n[i]); + } + + validator.SetIncludes (list); + + add_label_to_grid_bag_sizer (table, this, _("Matrix"), true, wxGBPosition (r, 0)); + wxFlexGridSizer* matrix_sizer = new wxFlexGridSizer (3, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP); + for (int x = 0; x < 3; ++x) { + for (int y = 0; y < 3; ++y) { + _matrix[x][y] = new wxTextCtrl (this, wxID_ANY, wxT (""), wxDefaultPosition, size, 0, validator); + matrix_sizer->Add (_matrix[x][y]); + } + } + table->Add (matrix_sizer, wxGBPosition (r, 1)); + ++r; + + add_label_to_grid_bag_sizer (table, this, _("Output gamma"), true, wxGBPosition (r, 0)); + wxBoxSizer* output_sizer = new wxBoxSizer (wxHORIZONTAL); + /* TRANSLATORS: this means the mathematical reciprocal operation, i.e. we are dividing 1 by the control that + comes after it. + */ + add_label_to_sizer (output_sizer, this, _("1 / "), false); + _output_gamma = new wxSpinCtrlDouble (this); + output_sizer->Add (_output_gamma); + table->Add (output_sizer, wxGBPosition (r, 1)); + ++r; + + wxSizer* buttons = CreateSeparatedButtonSizer (wxOK); + if (buttons) { + overall_sizer->Add (buttons, wxSizerFlags().Expand().DoubleBorder()); + } + + SetSizer (overall_sizer); + overall_sizer->Layout (); + overall_sizer->SetSizeHints (this); + + _input_gamma->SetRange(0.1, 4.0); + _input_gamma->SetDigits (1); + _input_gamma->SetIncrement (0.1); + _output_gamma->SetRange(0.1, 4.0); + _output_gamma->SetDigits (1); + _output_gamma->SetIncrement (0.1); + + _name->SetValue (std_to_wx (conversion->name)); + _input_gamma->SetValue (conversion->input_gamma); + _input_gamma_linearised->SetValue (conversion->input_gamma_linearised); + for (int i = 0; i < 3; ++i) { + for (int j = 0; j < 3; ++j) { + _matrix[i][j]->SetValue (std_to_wx (lexical_cast (conversion->matrix(i, j)))); + } + } + _output_gamma->SetValue (conversion->output_gamma); + + _name->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&ColourConversionDialog::changed, this)); + _input_gamma->Bind (wxEVT_COMMAND_SPINCTRLDOUBLE_UPDATED, boost::bind (&ColourConversionDialog::changed, this)); + _input_gamma_linearised->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&ColourConversionDialog::changed, this)); + _output_gamma->Bind (wxEVT_COMMAND_SPINCTRLDOUBLE_UPDATED, boost::bind (&ColourConversionDialog::changed, this)); + for (int i = 0; i < 3; ++i) { + for (int j = 0; j < 3; ++j) { + _matrix[i][j]->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&ColourConversionDialog::changed, this)); + } + } +} + +void +ColourConversionDialog::changed () +{ + _conversion->name = wx_to_std (_name->GetValue ()); + _conversion->input_gamma = _input_gamma->GetValue (); + _conversion->input_gamma_linearised = _input_gamma_linearised->GetValue (); + + for (int i = 0; i < 3; ++i) { + for (int j = 0; j < 3; ++j) { + string const v = wx_to_std (_matrix[i][j]->GetValue ()); + if (v.empty ()) { + _conversion->matrix (i, j) = 0; + } else { + _conversion->matrix (i, j) = lexical_cast (v); + } + } + } + _conversion->output_gamma = _output_gamma->GetValue (); +} + diff --git a/src/wx/colour_conversion_dialog.h b/src/wx/colour_conversion_dialog.h new file mode 100644 index 000000000..8da6df100 --- /dev/null +++ b/src/wx/colour_conversion_dialog.h @@ -0,0 +1,39 @@ +/* + 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 + +class wxSpinCtrlDouble; +class ColourConversion; + +class ColourConversionDialog : public wxDialog +{ +public: + ColourConversionDialog (wxWindow *, boost::shared_ptr); + +private: + void changed (); + + boost::shared_ptr _conversion; + wxTextCtrl* _name; + wxSpinCtrlDouble* _input_gamma; + wxCheckBox* _input_gamma_linearised; + wxTextCtrl* _matrix[3][3]; + wxSpinCtrlDouble* _output_gamma; +}; diff --git a/src/wx/config_dialog.cc b/src/wx/config_dialog.cc index cbcae78f8..66f0cd186 100644 --- a/src/wx/config_dialog.cc +++ b/src/wx/config_dialog.cc @@ -26,21 +26,28 @@ #include #include #include +#include #include "lib/config.h" #include "lib/server.h" #include "lib/ratio.h" #include "lib/scaler.h" #include "lib/filter.h" #include "lib/dcp_content_type.h" +#include "lib/colour_conversion.h" #include "config_dialog.h" #include "wx_util.h" #include "filter_dialog.h" #include "server_dialog.h" #include "dir_picker_ctrl.h" #include "dci_metadata_dialog.h" +#include "colour_conversion_dialog.h" -using namespace std; +using std::vector; +using std::string; +using std::list; using boost::bind; +using boost::shared_ptr; +using boost::lexical_cast; ConfigDialog::ConfigDialog (wxWindow* parent) : wxDialog (parent, wxID_ANY, _("DCP-o-matic Preferences"), wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER) @@ -53,6 +60,8 @@ ConfigDialog::ConfigDialog (wxWindow* parent) _notebook->AddPage (_misc_panel, _("Miscellaneous"), true); make_servers_panel (); _notebook->AddPage (_servers_panel, _("Encoding servers"), false); + make_colour_conversions_panel (); + _notebook->AddPage (_colour_conversions_panel, _("Colour conversions"), false); make_metadata_panel (); _notebook->AddPage (_metadata_panel, _("Metadata"), false); make_tms_panel (); @@ -270,54 +279,32 @@ ConfigDialog::make_metadata_panel () _creator->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&ConfigDialog::creator_changed, this)); } -void -ConfigDialog::make_servers_panel () +static std::string +server_column (shared_ptr s, int c) { - _servers_panel = new wxPanel (_notebook); - wxBoxSizer* s = new wxBoxSizer (wxVERTICAL); - _servers_panel->SetSizer (s); - - wxFlexGridSizer* table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP); - table->AddGrowableCol (0, 1); - s->Add (table, 1, wxALL | wxEXPAND, 8); - - Config* config = Config::instance (); - - _servers = new wxListCtrl (_servers_panel, wxID_ANY, wxDefaultPosition, wxSize (220, 100), wxLC_REPORT | wxLC_SINGLE_SEL); - wxListItem ip; - ip.SetId (0); - ip.SetText (_("IP address")); - ip.SetWidth (120); - _servers->InsertColumn (0, ip); - ip.SetId (1); - ip.SetText (_("Threads")); - ip.SetWidth (80); - _servers->InsertColumn (1, ip); - table->Add (_servers, 1, wxEXPAND | wxALL); - - { - wxSizer* s = new wxBoxSizer (wxVERTICAL); - _add_server = new wxButton (_servers_panel, wxID_ANY, _("Add")); - s->Add (_add_server, 0, wxTOP | wxBOTTOM, 2); - _edit_server = new wxButton (_servers_panel, wxID_ANY, _("Edit")); - s->Add (_edit_server, 0, wxTOP | wxBOTTOM, 2); - _remove_server = new wxButton (_servers_panel, wxID_ANY, _("Remove")); - s->Add (_remove_server, 0, wxTOP | wxBOTTOM, 2); - table->Add (s, 0); + switch (c) { + case 0: + return s->host_name (); + case 1: + return lexical_cast (s->threads ()); } - vector servers = config->servers (); - for (vector::iterator i = servers.begin(); i != servers.end(); ++i) { - add_server_to_control (*i); - } - - _add_server->Bind (wxEVT_COMMAND_BUTTON_CLICKED, boost::bind (&ConfigDialog::add_server_clicked, this)); - _edit_server->Bind (wxEVT_COMMAND_BUTTON_CLICKED, boost::bind (&ConfigDialog::edit_server_clicked, this)); - _remove_server->Bind (wxEVT_COMMAND_BUTTON_CLICKED, boost::bind (&ConfigDialog::remove_server_clicked, this)); + return ""; +} - _servers->Bind (wxEVT_COMMAND_LIST_ITEM_SELECTED, boost::bind (&ConfigDialog::server_selection_changed, this)); - _servers->Bind (wxEVT_COMMAND_LIST_ITEM_DESELECTED, boost::bind (&ConfigDialog::server_selection_changed, this)); - server_selection_changed (); +void +ConfigDialog::make_servers_panel () +{ + vector columns; + columns.push_back (wx_to_std (_("IP address"))); + columns.push_back (wx_to_std (_("Threads"))); + _servers_panel = new EditableList ( + _notebook, + columns, + boost::bind (&Config::servers, Config::instance()), + boost::bind (&Config::set_servers, Config::instance(), _1), + boost::bind (&server_column, _1, _2) + ); } void @@ -378,76 +365,6 @@ ConfigDialog::default_directory_changed () Config::instance()->set_default_directory (wx_to_std (_default_directory->GetPath ())); } -void -ConfigDialog::add_server_to_control (ServerDescription* s) -{ - wxListItem item; - int const n = _servers->GetItemCount (); - item.SetId (n); - _servers->InsertItem (item); - _servers->SetItem (n, 0, std_to_wx (s->host_name ())); - _servers->SetItem (n, 1, std_to_wx (boost::lexical_cast (s->threads ()))); -} - -void -ConfigDialog::add_server_clicked () -{ - ServerDialog* d = new ServerDialog (this, 0); - d->ShowModal (); - ServerDescription* s = d->server (); - d->Destroy (); - - add_server_to_control (s); - vector o = Config::instance()->servers (); - o.push_back (s); - Config::instance()->set_servers (o); -} - -void -ConfigDialog::edit_server_clicked () -{ - int i = _servers->GetNextItem (-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED); - if (i == -1) { - return; - } - - wxListItem item; - item.SetId (i); - item.SetColumn (0); - _servers->GetItem (item); - - vector servers = Config::instance()->servers (); - assert (i >= 0 && i < int (servers.size ())); - - ServerDialog* d = new ServerDialog (this, servers[i]); - d->ShowModal (); - d->Destroy (); - - _servers->SetItem (i, 0, std_to_wx (servers[i]->host_name ())); - _servers->SetItem (i, 1, std_to_wx (boost::lexical_cast (servers[i]->threads ()))); -} - -void -ConfigDialog::remove_server_clicked () -{ - int i = _servers->GetNextItem (-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED); - if (i >= 0) { - _servers->DeleteItem (i); - } - - vector o = Config::instance()->servers (); - o.erase (o.begin() + i); - Config::instance()->set_servers (o); -} - -void -ConfigDialog::server_selection_changed () -{ - int const i = _servers->GetNextItem (-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED); - _edit_server->Enable (i >= 0); - _remove_server->Enable (i >= 0); -} - void ConfigDialog::edit_default_dci_metadata_clicked () { @@ -515,3 +432,23 @@ ConfigDialog::default_j2k_bandwidth_changed () { Config::instance()->set_default_j2k_bandwidth (_default_j2k_bandwidth->GetValue() * 1e6); } + +static std::string +colour_conversion_column (shared_ptr c) +{ + return c->name; +} + +void +ConfigDialog::make_colour_conversions_panel () +{ + vector columns; + columns.push_back (wx_to_std (_("Name"))); + _colour_conversions_panel = new EditableList ( + _notebook, + columns, + boost::bind (&Config::colour_conversions, Config::instance()), + boost::bind (&Config::set_colour_conversions, Config::instance(), _1), + boost::bind (&colour_conversion_column, _1) + ); +} diff --git a/src/wx/config_dialog.h b/src/wx/config_dialog.h index 444b886f4..60d9229c4 100644 --- a/src/wx/config_dialog.h +++ b/src/wx/config_dialog.h @@ -26,11 +26,14 @@ #include #include #include "wx_util.h" +#include "editable_list.h" class DirPickerCtrl; class wxNotebook; - class ServerDescription; +class ColourConversion; +class ColourConversionDialog; +class ServerDialog; /** @class ConfigDialog * @brief A dialogue to edit DCP-o-matic configuration. @@ -51,28 +54,25 @@ private: void default_still_length_changed (); void default_directory_changed (); void edit_default_dci_metadata_clicked (); - void add_server_clicked (); - void edit_server_clicked (); - void remove_server_clicked (); - void server_selection_changed (); void default_container_changed (); void default_dcp_content_type_changed (); void issuer_changed (); void creator_changed (); void default_j2k_bandwidth_changed (); - void add_server_to_control (ServerDescription *); void setup_language_sensitivity (); void make_misc_panel (); void make_tms_panel (); void make_metadata_panel (); void make_servers_panel (); + void make_colour_conversions_panel (); wxNotebook* _notebook; wxPanel* _misc_panel; wxPanel* _tms_panel; - wxPanel* _servers_panel; + EditableList* _colour_conversions_panel; + EditableList* _servers_panel; wxPanel* _metadata_panel; wxCheckBox* _set_language; wxChoice* _language; @@ -90,10 +90,6 @@ private: wxDirPickerCtrl* _default_directory; #endif wxButton* _default_dci_metadata_button; - wxListCtrl* _servers; - wxButton* _add_server; - wxButton* _edit_server; - wxButton* _remove_server; wxTextCtrl* _issuer; wxTextCtrl* _creator; wxSpinCtrl* _default_j2k_bandwidth; diff --git a/src/wx/editable_list.h b/src/wx/editable_list.h new file mode 100644 index 000000000..32cc326b6 --- /dev/null +++ b/src/wx/editable_list.h @@ -0,0 +1,156 @@ +/* + Copyright (C) 2012 Carl Hetherington + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#include + +template +class EditableList : public wxPanel +{ +public: + EditableList ( + wxWindow* parent, + std::vector columns, + boost::function > ()> get, + boost::function >)> set, + boost::function, int)> column + ) + : wxPanel (parent) + , _get (get) + , _set (set) + , _columns (columns.size ()) + , _column (column) + { + wxBoxSizer* s = new wxBoxSizer (wxVERTICAL); + SetSizer (s); + + wxFlexGridSizer* table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP); + table->AddGrowableCol (0, 1); + s->Add (table, 1, wxALL | wxEXPAND, 8); + + _list = new wxListCtrl (this, wxID_ANY, wxDefaultPosition, wxSize (columns.size() * 200, 100), wxLC_REPORT | wxLC_SINGLE_SEL); + + for (size_t i = 0; i < columns.size(); ++i) { + wxListItem ip; + ip.SetId (i); + ip.SetText (std_to_wx (columns[i])); + ip.SetWidth (200); + _list->InsertColumn (i, ip); + } + + table->Add (_list, 1, wxEXPAND | wxALL); + + { + wxSizer* s = new wxBoxSizer (wxVERTICAL); + _add = new wxButton (this, wxID_ANY, _("Add...")); + s->Add (_add, 0, wxTOP | wxBOTTOM, 2); + _edit = new wxButton (this, wxID_ANY, _("Edit...")); + s->Add (_edit, 0, wxTOP | wxBOTTOM, 2); + _remove = new wxButton (this, wxID_ANY, _("Remove")); + s->Add (_remove, 0, wxTOP | wxBOTTOM, 2); + table->Add (s, 0); + } + + std::vector > current = _get (); + for (typename std::vector >::iterator i = current.begin (); i != current.end(); ++i) { + add_to_control (*i); + } + + _add->Bind (wxEVT_COMMAND_BUTTON_CLICKED, boost::bind (&EditableList::add_clicked, this)); + _edit->Bind (wxEVT_COMMAND_BUTTON_CLICKED, boost::bind (&EditableList::edit_clicked, this)); + _remove->Bind (wxEVT_COMMAND_BUTTON_CLICKED, boost::bind (&EditableList::remove_clicked, this)); + + _list->Bind (wxEVT_COMMAND_LIST_ITEM_SELECTED, boost::bind (&EditableList::selection_changed, this)); + _list->Bind (wxEVT_COMMAND_LIST_ITEM_DESELECTED, boost::bind (&EditableList::selection_changed, this)); + selection_changed (); + } + + void add_to_control (boost::shared_ptr item) + { + wxListItem list_item; + int const n = _list->GetItemCount (); + list_item.SetId (n); + _list->InsertItem (list_item); + + for (int i = 0; i < _columns; ++i) { + _list->SetItem (n, i, std_to_wx (_column (item, i))); + } + } + + void selection_changed () + { + int const i = _list->GetNextItem (-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED); + _edit->Enable (i >= 0); + _remove->Enable (i >= 0); + } + + void add_clicked () + { + boost::shared_ptr new_item (new T); + S* dialog = new S (this, new_item); + dialog->ShowModal (); + dialog->Destroy (); + + add_to_control (new_item); + std::vector > all = _get (); + all.push_back (new_item); + _set (all); + } + + void edit_clicked () + { + int item = _list->GetNextItem (-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED); + if (item == -1) { + return; + } + + std::vector > all = _get (); + assert (item >= 0 && item < int (all.size ())); + + S* dialog = new S (this, all[item]); + dialog->ShowModal (); + dialog->Destroy (); + + for (int i = 0; i < _columns; ++i) { + _list->SetItem (item, i, std_to_wx (_column (all[item], i))); + } + } + + void remove_clicked () + { + int i = _list->GetNextItem (-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED); + if (i >= 0) { + _list->DeleteItem (i); + } + + std::vector > all = _get (); + all.erase (all.begin() + i); + _set (all); + } + +private: + boost::function > ()> _get; + boost::function >)> _set; + int _columns; + boost::function, int)> _column; + + wxButton* _add; + wxButton* _edit; + wxButton* _remove; + wxListCtrl* _list; +}; diff --git a/src/wx/server_dialog.cc b/src/wx/server_dialog.cc index 0f41b5b90..a0f1f04ae 100644 --- a/src/wx/server_dialog.cc +++ b/src/wx/server_dialog.cc @@ -21,13 +21,15 @@ #include "server_dialog.h" #include "wx_util.h" -ServerDialog::ServerDialog (wxWindow* parent, ServerDescription* server) +using boost::shared_ptr; + +ServerDialog::ServerDialog (wxWindow* parent, shared_ptr server) : wxDialog (parent, wxID_ANY, _("Server")) { if (server) { _server = server; } else { - _server = new ServerDescription (wx_to_std (N_("localhost")), 1); + _server.reset (new ServerDescription (wx_to_std (N_("localhost")), 1)); } wxFlexGridSizer* table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP); @@ -73,7 +75,7 @@ ServerDialog::threads_changed () _server->set_threads (_threads->GetValue ()); } -ServerDescription * +shared_ptr ServerDialog::server () const { return _server; diff --git a/src/wx/server_dialog.h b/src/wx/server_dialog.h index f42236771..3f1fa1f73 100644 --- a/src/wx/server_dialog.h +++ b/src/wx/server_dialog.h @@ -25,15 +25,15 @@ class ServerDescription; class ServerDialog : public wxDialog { public: - ServerDialog (wxWindow *, ServerDescription *); + ServerDialog (wxWindow *, boost::shared_ptr); - ServerDescription* server () const; + boost::shared_ptr server () const; private: void host_changed (); void threads_changed (); - ServerDescription* _server; + boost::shared_ptr _server; wxTextCtrl* _host; wxSpinCtrl* _threads; }; diff --git a/src/wx/video_panel.cc b/src/wx/video_panel.cc index 0c2702913..5ba06b12d 100644 --- a/src/wx/video_panel.cc +++ b/src/wx/video_panel.cc @@ -21,6 +21,8 @@ #include "lib/ratio.h" #include "lib/filter.h" #include "lib/ffmpeg_content.h" +#include "lib/colour_conversion.h" +#include "lib/config.h" #include "filter_dialog.h" #include "video_panel.h" #include "wx_util.h" @@ -30,6 +32,7 @@ using std::vector; using std::string; using std::pair; using std::cout; +using std::list; using boost::shared_ptr; using boost::dynamic_pointer_cast; using boost::bind; @@ -83,6 +86,11 @@ VideoPanel::VideoPanel (FilmEditor* e) } ++r; + add_label_to_grid_bag_sizer (grid, this, _("Colour conversion"), true, wxGBPosition (r, 0)); + _colour_conversion = new wxChoice (this, wxID_ANY); + grid->Add (_colour_conversion, wxGBPosition (r, 1)); + ++r; + _description = new wxStaticText (this, wxID_ANY, wxT ("\n \n \n \n \n"), wxDefaultPosition, wxDefaultSize); grid->Add (_description, wxGBPosition (r, 0), wxGBSpan (1, 2), wxEXPAND | wxALIGN_CENTER_VERTICAL | wxALL, 6); wxFont font = _description->GetFont(); @@ -105,13 +113,16 @@ VideoPanel::VideoPanel (FilmEditor* e) _frame_type->Append (_("2D")); _frame_type->Append (_("3D left/right")); - _frame_type->Bind (wxEVT_COMMAND_CHOICE_SELECTED, boost::bind (&VideoPanel::frame_type_changed, this)); - _left_crop->Bind (wxEVT_COMMAND_SPINCTRL_UPDATED, boost::bind (&VideoPanel::left_crop_changed, this)); - _right_crop->Bind (wxEVT_COMMAND_SPINCTRL_UPDATED, boost::bind (&VideoPanel::right_crop_changed, this)); - _top_crop->Bind (wxEVT_COMMAND_SPINCTRL_UPDATED, boost::bind (&VideoPanel::top_crop_changed, this)); - _bottom_crop->Bind (wxEVT_COMMAND_SPINCTRL_UPDATED, boost::bind (&VideoPanel::bottom_crop_changed, this)); - _ratio->Bind (wxEVT_COMMAND_CHOICE_SELECTED, boost::bind (&VideoPanel::ratio_changed, this)); - _filters_button->Bind (wxEVT_COMMAND_BUTTON_CLICKED, boost::bind (&VideoPanel::edit_filters_clicked, this)); + setup_colour_conversions (); + + _frame_type->Bind (wxEVT_COMMAND_CHOICE_SELECTED, boost::bind (&VideoPanel::frame_type_changed, this)); + _left_crop->Bind (wxEVT_COMMAND_SPINCTRL_UPDATED, boost::bind (&VideoPanel::left_crop_changed, this)); + _right_crop->Bind (wxEVT_COMMAND_SPINCTRL_UPDATED, boost::bind (&VideoPanel::right_crop_changed, this)); + _top_crop->Bind (wxEVT_COMMAND_SPINCTRL_UPDATED, boost::bind (&VideoPanel::top_crop_changed, this)); + _bottom_crop->Bind (wxEVT_COMMAND_SPINCTRL_UPDATED, boost::bind (&VideoPanel::bottom_crop_changed, this)); + _ratio->Bind (wxEVT_COMMAND_CHOICE_SELECTED, boost::bind (&VideoPanel::ratio_changed, this)); + _filters_button->Bind (wxEVT_COMMAND_BUTTON_CLICKED, boost::bind (&VideoPanel::edit_filters_clicked, this)); + _colour_conversion->Bind (wxEVT_COMMAND_CHOICE_SELECTED, boost::bind (&VideoPanel::colour_conversion_changed, this)); } @@ -342,3 +353,18 @@ VideoPanel::frame_type_changed () vc->set_video_frame_type (static_cast (_frame_type->GetSelection ())); } } + +void +VideoPanel::setup_colour_conversions () +{ + vector > cc = Config::instance()->colour_conversions (); + for (vector >::iterator i = cc.begin(); i != cc.end(); ++i) { + _colour_conversion->Append (std_to_wx ((*i)->name)); + } +} + +void +VideoPanel::colour_conversion_changed () +{ + +} diff --git a/src/wx/video_panel.h b/src/wx/video_panel.h index 5a2281150..62332a052 100644 --- a/src/wx/video_panel.h +++ b/src/wx/video_panel.h @@ -41,8 +41,10 @@ private: void edit_filters_clicked (); void ratio_changed (); void frame_type_changed (); + void colour_conversion_changed (); void setup_description (); + void setup_colour_conversions (); wxChoice* _frame_type; wxSpinCtrl* _left_crop; @@ -54,4 +56,5 @@ private: wxStaticText* _description; wxStaticText* _filters; wxButton* _filters_button; + wxChoice* _colour_conversion; }; diff --git a/src/wx/wscript b/src/wx/wscript index 883304eff..e0566a6ed 100644 --- a/src/wx/wscript +++ b/src/wx/wscript @@ -9,6 +9,7 @@ sources = """ audio_mapping_view.cc audio_panel.cc audio_plot.cc + colour_conversion_dialog.cc config_dialog.cc content_menu.cc dci_metadata_dialog.cc diff --git a/test/client_server_test.cc b/test/client_server_test.cc index 2dc1545d6..d695f96ce 100644 --- a/test/client_server_test.cc +++ b/test/client_server_test.cc @@ -29,7 +29,7 @@ using boost::shared_ptr; using boost::thread; void -do_remote_encode (shared_ptr frame, ServerDescription* description, shared_ptr locally_encoded) +do_remote_encode (shared_ptr frame, shared_ptr description, shared_ptr locally_encoded) { shared_ptr remotely_encoded; BOOST_CHECK_NO_THROW (remotely_encoded = frame->encode_remotely (description)); @@ -92,11 +92,11 @@ BOOST_AUTO_TEST_CASE (client_server_test) /* Let the server get itself ready */ dcpomatic_sleep (1); - ServerDescription description ("localhost", 2); + shared_ptr description (new ServerDescription ("localhost", 2)); list threads; for (int i = 0; i < 8; ++i) { - threads.push_back (new thread (boost::bind (do_remote_encode, frame, &description, locally_encoded))); + threads.push_back (new thread (boost::bind (do_remote_encode, frame, description, locally_encoded))); } for (list::iterator i = threads.begin(); i != threads.end(); ++i) { diff --git a/test/test.cc b/test/test.cc index 2334523a1..21cf18c76 100644 --- a/test/test.cc +++ b/test/test.cc @@ -46,7 +46,7 @@ struct TestConfig dcpomatic_setup(); Config::instance()->set_num_local_encoding_threads (1); - Config::instance()->set_servers (vector ()); + Config::instance()->set_servers (vector > ()); Config::instance()->set_server_port (61920); Config::instance()->set_default_dci_metadata (DCIMetadata ()); Config::instance()->set_default_container (static_cast (0)); -- cgit v1.2.3 From 2499c41097f8410cb3016e095a85d68979485a7b Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Sat, 17 Aug 2013 21:47:08 +0100 Subject: Various bits mostly related to colour conversions. --- platform/windows/installer.nsi.32.in | 6 +- platform/windows/installer.nsi.64.in | 6 +- src/lib/colour_conversion.cc | 96 ++++++++++++++++-- src/lib/colour_conversion.h | 35 +++++-- src/lib/config.cc | 26 +++-- src/lib/config.h | 15 +-- src/lib/dcp_video_frame.cc | 4 +- src/lib/dcp_video_frame.h | 2 +- src/lib/encoder.cc | 12 +-- src/lib/encoder.h | 2 +- src/lib/server.cc | 7 +- src/lib/server.h | 7 +- src/lib/video_content.cc | 28 +++++- src/lib/video_content.h | 10 ++ src/tools/dcpomatic_cli.cc | 2 +- src/wx/colour_conversion_dialog.cc | 150 ---------------------------- src/wx/colour_conversion_dialog.h | 39 -------- src/wx/colour_conversion_editor.cc | 152 +++++++++++++++++++++++++++++ src/wx/colour_conversion_editor.h | 48 +++++++++ src/wx/config_dialog.cc | 14 +-- src/wx/config_dialog.h | 6 +- src/wx/content_colour_conversion_dialog.cc | 121 +++++++++++++++++++++++ src/wx/content_colour_conversion_dialog.h | 41 ++++++++ src/wx/editable_list.h | 57 +++++++---- src/wx/film_editor.cc | 1 + src/wx/filter_dialog.cc | 4 +- src/wx/filter_dialog.h | 4 +- src/wx/filter_editor.cc | 92 +++++++++++++++++ src/wx/filter_editor.h | 47 +++++++++ src/wx/filter_view.cc | 92 ----------------- src/wx/filter_view.h | 47 --------- src/wx/preset_colour_conversion_dialog.cc | 68 +++++++++++++ src/wx/preset_colour_conversion_dialog.h | 35 +++++++ src/wx/server_dialog.cc | 33 ++----- src/wx/server_dialog.h | 9 +- src/wx/video_panel.cc | 67 ++++++++----- src/wx/video_panel.h | 6 +- src/wx/wscript | 6 +- test/client_server_test.cc | 4 +- test/test.cc | 2 +- 40 files changed, 919 insertions(+), 484 deletions(-) delete mode 100644 src/wx/colour_conversion_dialog.cc delete mode 100644 src/wx/colour_conversion_dialog.h create mode 100644 src/wx/colour_conversion_editor.cc create mode 100644 src/wx/colour_conversion_editor.h create mode 100644 src/wx/content_colour_conversion_dialog.cc create mode 100644 src/wx/content_colour_conversion_dialog.h create mode 100644 src/wx/filter_editor.cc create mode 100644 src/wx/filter_editor.h delete mode 100644 src/wx/filter_view.cc delete mode 100644 src/wx/filter_view.h create mode 100644 src/wx/preset_colour_conversion_dialog.cc create mode 100644 src/wx/preset_colour_conversion_dialog.h (limited to 'src/lib/server.cc') diff --git a/platform/windows/installer.nsi.32.in b/platform/windows/installer.nsi.32.in index 30cfd806d..938024d57 100644 --- a/platform/windows/installer.nsi.32.in +++ b/platform/windows/installer.nsi.32.in @@ -48,9 +48,9 @@ File "%deps%/bin/libglib-2.0-0.dll" File "%deps%/bin/libgobject-2.0-0.dll" File "%deps%/bin/libiconv-2.dll" File "%deps%/bin/libjpeg-8.dll" -File "%deps%/bin/libMagick++-5.dll" -File "%deps%/bin/libMagickCore-5.dll" -File "%deps%/bin/libMagickWand-5.dll" +File "%deps%/bin/libMagick++-6.Q16-2.dll" +File "%deps%/bin/libMagickCore-6.Q16-1.dll" +File "%deps%/bin/libMagickWand-6.Q16-1.dll" File "%deps%/bin/libopenjpeg-1.dll" File "%deps%/bin/libpng15-15.dll" File "%deps%/bin/libsigc-2.0-0.dll" diff --git a/platform/windows/installer.nsi.64.in b/platform/windows/installer.nsi.64.in index 3cc54b4fc..941e1c047 100644 --- a/platform/windows/installer.nsi.64.in +++ b/platform/windows/installer.nsi.64.in @@ -58,9 +58,9 @@ File "%deps%/bin/libglib-2.0-0.dll" File "%deps%/bin/libgobject-2.0-0.dll" File "%deps%/bin/libiconv-2.dll" File "%deps%/bin/libjpeg-8.dll" -File "%deps%/bin/libMagick++-5.dll" -File "%deps%/bin/libMagickCore-5.dll" -File "%deps%/bin/libMagickWand-5.dll" +File "%deps%/bin/libMagick++-6.Q16-2.dll" +File "%deps%/bin/libMagickCore-6.Q16-1.dll" +File "%deps%/bin/libMagickWand-6.Q16-1.dll" File "%deps%/bin/libopenjpeg-1.dll" File "%deps%/bin/libpng15-15.dll" File "%deps%/bin/libsigc-2.0-0.dll" diff --git a/src/lib/colour_conversion.cc b/src/lib/colour_conversion.cc index 96dc0e2c9..cc25ccc67 100644 --- a/src/lib/colour_conversion.cc +++ b/src/lib/colour_conversion.cc @@ -21,18 +21,21 @@ #include #include #include +#include "config.h" #include "colour_conversion.h" #include "i18n.h" using std::list; using std::string; +using std::cout; +using std::vector; using boost::shared_ptr; using boost::lexical_cast; +using boost::optional; ColourConversion::ColourConversion () - : name (_("Untitled")) - , input_gamma (2.4) + : input_gamma (2.4) , input_gamma_linearised (true) , matrix (3, 3) , output_gamma (2.6) @@ -44,9 +47,8 @@ ColourConversion::ColourConversion () } } -ColourConversion::ColourConversion (string n, float i, bool il, float const m[3][3], float o) - : name (n) - , input_gamma (i) +ColourConversion::ColourConversion (double i, bool il, double const m[3][3], double o) + : input_gamma (i) , input_gamma_linearised (il) , matrix (3, 3) , output_gamma (o) @@ -61,8 +63,7 @@ ColourConversion::ColourConversion (string n, float i, bool il, float const m[3] ColourConversion::ColourConversion (shared_ptr node) : matrix (3, 3) { - name = node->string_child ("Name"); - input_gamma = node->number_child ("InputGamma"); + input_gamma = node->number_child ("InputGamma"); input_gamma_linearised = node->bool_child ("InputGammaLinearised"); for (int i = 0; i < 3; ++i) { @@ -75,16 +76,15 @@ ColourConversion::ColourConversion (shared_ptr node) for (list >::iterator i = m.begin(); i != m.end(); ++i) { int const ti = (*i)->number_attribute ("i"); int const tj = (*i)->number_attribute ("j"); - matrix(ti, tj) = lexical_cast ((*i)->content ()); + matrix(ti, tj) = lexical_cast ((*i)->content ()); } - output_gamma = node->number_child ("OutputGamma"); + output_gamma = node->number_child ("OutputGamma"); } void ColourConversion::as_xml (xmlpp::Node* node) const { - node->add_child("Name")->add_child_text (name); node->add_child("InputGamma")->add_child_text (lexical_cast (input_gamma)); node->add_child("InputGammaLinearised")->add_child_text (input_gamma_linearised ? "1" : "0"); @@ -99,3 +99,79 @@ ColourConversion::as_xml (xmlpp::Node* node) const node->add_child("OutputGamma")->add_child_text (lexical_cast (output_gamma)); } + +optional +ColourConversion::preset () const +{ + vector presets = Config::instance()->colour_conversions (); + size_t i = 0; + while (i < presets.size() && (presets[i].conversion != *this)) { + ++i; + } + + if (i >= presets.size ()) { + return optional (); + } + + return i; +} + +PresetColourConversion::PresetColourConversion () + : name (_("Untitled")) +{ + +} + +PresetColourConversion::PresetColourConversion (string n, double i, bool il, double const m[3][3], double o) + : name (n) + , conversion (i, il, m, o) +{ + +} + +PresetColourConversion::PresetColourConversion (shared_ptr node) + : conversion (node) +{ + name = node->string_child ("Name"); +} + +void +PresetColourConversion::as_xml (xmlpp::Node* node) const +{ + conversion.as_xml (node); + node->add_child("Name")->add_child_text (name); +} + +static bool +about_equal (double a, double b) +{ + static const double eps = 1e-6; + return fabs (a - b) < eps; +} + +bool +operator== (ColourConversion const & a, ColourConversion const & b) +{ + if ( + !about_equal (a.input_gamma, b.input_gamma) || + a.input_gamma_linearised != b.input_gamma_linearised || + !about_equal (a.output_gamma, b.output_gamma)) { + return false; + } + + for (int i = 0; i < 3; ++i) { + for (int j = 0; j < 3; ++j) { + if (!about_equal (a.matrix (i, j), b.matrix (i, j))) { + return false; + } + } + } + + return true; +} + +bool +operator!= (ColourConversion const & a, ColourConversion const & b) +{ + return !(a == b); +} diff --git a/src/lib/colour_conversion.h b/src/lib/colour_conversion.h index ed89f8c63..85d951ce1 100644 --- a/src/lib/colour_conversion.h +++ b/src/lib/colour_conversion.h @@ -17,7 +17,11 @@ */ +#ifndef DCPOMATIC_COLOUR_CONVERSION_H +#define DCPOMATIC_COLOUR_CONVERSION_H + #include +#include #include namespace cxml { @@ -28,18 +32,37 @@ namespace xmlpp { class Node; } -class ColourConversion : public boost::noncopyable +class ColourConversion { public: ColourConversion (); - ColourConversion (std::string, float, bool, float const matrix[3][3], float); + ColourConversion (double, bool, double const matrix[3][3], double); ColourConversion (boost::shared_ptr); + virtual void as_xml (xmlpp::Node *) const; + + boost::optional preset () const; + + double input_gamma; + bool input_gamma_linearised; + boost::numeric::ublas::matrix matrix; + double output_gamma; +}; + +class PresetColourConversion +{ +public: + PresetColourConversion (); + PresetColourConversion (std::string, double, bool, double const matrix[3][3], double); + PresetColourConversion (boost::shared_ptr); + void as_xml (xmlpp::Node *) const; std::string name; - float input_gamma; - bool input_gamma_linearised; - boost::numeric::ublas::matrix matrix; - float output_gamma; + ColourConversion conversion; }; + +bool operator== (ColourConversion const &, ColourConversion const &); +bool operator!= (ColourConversion const &, ColourConversion const &); + +#endif diff --git a/src/lib/config.cc b/src/lib/config.cc index 0c8413be9..10cb13ecc 100644 --- a/src/lib/config.cc +++ b/src/lib/config.cc @@ -65,13 +65,8 @@ Config::Config () _allowed_dcp_frame_rates.push_back (50); _allowed_dcp_frame_rates.push_back (60); - _colour_conversions.push_back (shared_ptr ( - new ColourConversion (_("sRGB"), 2.4, true, libdcp::colour_matrix::xyz_to_rgb, 2.6)) - ); - - _colour_conversions.push_back (shared_ptr ( - new ColourConversion (_("sRGB non-linearised"), 2.4, false, libdcp::colour_matrix::xyz_to_rgb, 2.6)) - ); + _colour_conversions.push_back (PresetColourConversion (_("sRGB"), 2.4, true, libdcp::colour_matrix::xyz_to_rgb, 2.6)); + _colour_conversions.push_back (PresetColourConversion (_("sRGB non-linearised"), 2.4, false, libdcp::colour_matrix::xyz_to_rgb, 2.6)); } void @@ -91,7 +86,7 @@ Config::read () list > servers = f.node_children ("Server"); for (list >::iterator i = servers.begin(); i != servers.end(); ++i) { - _servers.push_back (shared_ptr (new ServerDescription (*i))); + _servers.push_back (ServerDescription (*i)); } _tms_ip = f.string_child ("TMSIP"); @@ -130,7 +125,7 @@ Config::read () } for (list >::iterator i = cc.begin(); i != cc.end(); ++i) { - _colour_conversions.push_back (shared_ptr (new ColourConversion (*i))); + _colour_conversions.push_back (PresetColourConversion (*i)); } } @@ -163,7 +158,10 @@ Config::read_old_metadata () } else if (k == N_("server_port")) { _server_port = atoi (v.c_str ()); } else if (k == N_("server")) { - _servers.push_back (ServerDescription::create_from_metadata (v)); + optional server = ServerDescription::create_from_metadata (v); + if (server) { + _servers.push_back (server.get ()); + } } else if (k == N_("tms_ip")) { _tms_ip = v; } else if (k == N_("tms_path")) { @@ -237,8 +235,8 @@ Config::write () const root->add_child("DefaultDirectory")->add_child_text (_default_directory); root->add_child("ServerPort")->add_child_text (lexical_cast (_server_port)); - for (vector >::const_iterator i = _servers.begin(); i != _servers.end(); ++i) { - (*i)->as_xml (root->add_child ("Server")); + for (vector::const_iterator i = _servers.begin(); i != _servers.end(); ++i) { + i->as_xml (root->add_child ("Server")); } root->add_child("TMSIP")->add_child_text (_tms_ip); @@ -265,8 +263,8 @@ Config::write () const root->add_child("DefaultStillLength")->add_child_text (lexical_cast (_default_still_length)); root->add_child("DefaultJ2KBandwidth")->add_child_text (lexical_cast (_default_j2k_bandwidth)); - for (vector >::const_iterator i = _colour_conversions.begin(); i != _colour_conversions.end(); ++i) { - (*i)->as_xml (root->add_child ("ColourConversion")); + for (vector::const_iterator i = _colour_conversions.begin(); i != _colour_conversions.end(); ++i) { + i->as_xml (root->add_child ("ColourConversion")); } doc.write_to_file_formatted (file (false)); diff --git a/src/lib/config.h b/src/lib/config.h index 40d06a172..bce6bfd7e 100644 --- a/src/lib/config.h +++ b/src/lib/config.h @@ -29,6 +29,8 @@ #include #include #include "dci_metadata.h" +#include "colour_conversion.h" +#include "server.h" class ServerDescription; class Scaler; @@ -36,7 +38,6 @@ class Filter; class SoundProcessor; class DCPContentType; class Ratio; -class ColourConversion; /** @class Config * @brief A singleton class holding configuration. @@ -62,7 +63,7 @@ public: } /** @return J2K encoding servers to use */ - std::vector > servers () const { + std::vector servers () const { return _servers; } @@ -123,7 +124,7 @@ public: return _default_j2k_bandwidth; } - std::vector > colour_conversions () const { + std::vector colour_conversions () const { return _colour_conversions; } @@ -142,7 +143,7 @@ public: } /** @param s New list of servers */ - void set_servers (std::vector > s) { + void set_servers (std::vector s) { _servers = s; } @@ -210,7 +211,7 @@ public: _default_j2k_bandwidth = b; } - void set_colour_conversions (std::vector > const & c) { + void set_colour_conversions (std::vector const & c) { _colour_conversions = c; } @@ -233,7 +234,7 @@ private: int _server_port; /** J2K encoding servers to use */ - std::vector > _servers; + std::vector _servers; /** Scaler to use for the "A" part of A/B comparisons */ Scaler const * _reference_scaler; /** Filters to use for the "A" part of A/B comparisons */ @@ -257,7 +258,7 @@ private: DCPContentType const * _default_dcp_content_type; libdcp::XMLMetadata _dcp_metadata; int _default_j2k_bandwidth; - std::vector > _colour_conversions; + std::vector _colour_conversions; /** Singleton instance, or 0 */ static Config* _instance; diff --git a/src/lib/dcp_video_frame.cc b/src/lib/dcp_video_frame.cc index 53cf1753a..1cb20b611 100644 --- a/src/lib/dcp_video_frame.cc +++ b/src/lib/dcp_video_frame.cc @@ -213,11 +213,11 @@ DCPVideoFrame::encode_locally () * @return Encoded data. */ shared_ptr -DCPVideoFrame::encode_remotely (boost::shared_ptr serv) +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(), boost::lexical_cast (Config::instance()->server_port ())); + boost::asio::ip::tcp::resolver::query query (serv.host_name(), boost::lexical_cast (Config::instance()->server_port ())); boost::asio::ip::tcp::resolver::iterator endpoint_iterator = resolver.resolve (query); shared_ptr socket (new Socket); diff --git a/src/lib/dcp_video_frame.h b/src/lib/dcp_video_frame.h index 18c8fe628..ce6444293 100644 --- a/src/lib/dcp_video_frame.h +++ b/src/lib/dcp_video_frame.h @@ -105,7 +105,7 @@ public: DCPVideoFrame (boost::shared_ptr, int, Eyes, int, int, boost::shared_ptr); boost::shared_ptr encode_locally (); - boost::shared_ptr encode_remotely (boost::shared_ptr); + boost::shared_ptr encode_remotely (ServerDescription); Eyes eyes () const { return _eyes; diff --git a/src/lib/encoder.cc b/src/lib/encoder.cc index a1c024799..29fe64e26 100644 --- a/src/lib/encoder.cc +++ b/src/lib/encoder.cc @@ -71,13 +71,13 @@ void Encoder::process_begin () { for (int i = 0; i < Config::instance()->num_local_encoding_threads (); ++i) { - _threads.push_back (new boost::thread (boost::bind (&Encoder::encoder_thread, this, shared_ptr ()))); + _threads.push_back (new boost::thread (boost::bind (&Encoder::encoder_thread, this, optional ()))); } - vector > servers = Config::instance()->servers (); + vector servers = Config::instance()->servers (); - for (vector >::iterator i = servers.begin(); i != servers.end(); ++i) { - for (int j = 0; j < (*i)->threads (); ++j) { + for (vector::iterator i = servers.begin(); i != servers.end(); ++i) { + for (int j = 0; j < i->threads (); ++j) { _threads.push_back (new boost::thread (boost::bind (&Encoder::encoder_thread, this, *i))); } } @@ -244,7 +244,7 @@ Encoder::terminate_threads () } void -Encoder::encoder_thread (shared_ptr server) +Encoder::encoder_thread (optional server) { /* Number of seconds that we currently wait between attempts to connect to the server; not relevant for localhost @@ -275,7 +275,7 @@ Encoder::encoder_thread (shared_ptr server) if (server) { try { - encoded = vf->encode_remotely (server); + encoded = vf->encode_remotely (server.get ()); if (remote_backoff > 0) { _film->log()->log (String::compose (N_("%1 was lost, but now she is found; removing backoff"), server->host_name ())); diff --git a/src/lib/encoder.h b/src/lib/encoder.h index a4df202a2..c0ea30fcb 100644 --- a/src/lib/encoder.h +++ b/src/lib/encoder.h @@ -81,7 +81,7 @@ private: void frame_done (); - void encoder_thread (boost::shared_ptr); + void encoder_thread (boost::optional); void terminate_threads (); /** Film that we are encoding */ diff --git a/src/lib/server.cc b/src/lib/server.cc index 54cffc077..de265dca4 100644 --- a/src/lib/server.cc +++ b/src/lib/server.cc @@ -49,6 +49,7 @@ using boost::algorithm::split; using boost::thread; using boost::bind; using boost::scoped_array; +using boost::optional; using libdcp::Size; ServerDescription::ServerDescription (shared_ptr node) @@ -68,17 +69,17 @@ ServerDescription::as_xml (xmlpp::Node* root) const * @param v Metadata. * @return ServerDescription, or 0. */ -shared_ptr +optional ServerDescription::create_from_metadata (string v) { vector b; split (b, v, is_any_of (N_(" "))); if (b.size() != 2) { - return shared_ptr (); + return optional (); } - return shared_ptr (new ServerDescription (b[0], atoi (b[1].c_str ()))); + return ServerDescription (b[0], atoi (b[1].c_str ())); } Server::Server (shared_ptr log) diff --git a/src/lib/server.h b/src/lib/server.h index 6307c1867..56a1fdab9 100644 --- a/src/lib/server.h +++ b/src/lib/server.h @@ -17,6 +17,9 @@ */ +#ifndef DCPOMATIC_SERVER_H +#define DCPOMATIC_SERVER_H + /** @file src/server.h * @brief Class to describe a server to which we can send * encoding work, and a class to implement such a server. @@ -78,7 +81,7 @@ public: void as_xml (xmlpp::Node *) const; - static boost::shared_ptr create_from_metadata (std::string v); + static boost::optional create_from_metadata (std::string); private: /** server's host name */ @@ -104,3 +107,5 @@ private: boost::condition _worker_condition; boost::shared_ptr _log; }; + +#endif diff --git a/src/lib/video_content.cc b/src/lib/video_content.cc index f61518ec0..8b0ec4c99 100644 --- a/src/lib/video_content.cc +++ b/src/lib/video_content.cc @@ -23,14 +23,17 @@ #include "video_examiner.h" #include "ratio.h" #include "compose.hpp" +#include "config.h" +#include "colour_conversion.h" #include "i18n.h" -int const VideoContentProperty::VIDEO_SIZE = 0; -int const VideoContentProperty::VIDEO_FRAME_RATE = 1; -int const VideoContentProperty::VIDEO_FRAME_TYPE = 2; -int const VideoContentProperty::VIDEO_CROP = 3; -int const VideoContentProperty::VIDEO_RATIO = 4; +int const VideoContentProperty::VIDEO_SIZE = 0; +int const VideoContentProperty::VIDEO_FRAME_RATE = 1; +int const VideoContentProperty::VIDEO_FRAME_TYPE = 2; +int const VideoContentProperty::VIDEO_CROP = 3; +int const VideoContentProperty::VIDEO_RATIO = 4; +int const VideoContentProperty::COLOUR_CONVERSION = 5; using std::string; using std::stringstream; @@ -46,6 +49,7 @@ VideoContent::VideoContent (shared_ptr f, Time s, VideoContent::Fram , _video_frame_rate (0) , _video_frame_type (VIDEO_FRAME_TYPE_2D) , _ratio (Ratio::from_id ("185")) + , _colour_conversion (Config::instance()->colour_conversions().front().conversion) { } @@ -56,6 +60,7 @@ VideoContent::VideoContent (shared_ptr f, boost::filesystem::path p) , _video_frame_rate (0) , _video_frame_type (VIDEO_FRAME_TYPE_2D) , _ratio (Ratio::from_id ("185")) + , _colour_conversion (Config::instance()->colour_conversions().front().conversion) { } @@ -76,6 +81,7 @@ VideoContent::VideoContent (shared_ptr f, shared_ptrnode_child ("ColourConversion")); } void @@ -94,6 +100,7 @@ VideoContent::as_xml (xmlpp::Node* node) const if (_ratio) { node->add_child("Ratio")->add_child_text (_ratio->id ()); } + _colour_conversion.as_xml (node->add_child("ColourConversion")); } void @@ -257,3 +264,14 @@ VideoContent::video_size_after_3d_split () const assert (false); } + +void +VideoContent::set_colour_conversion (ColourConversion c) +{ + { + boost::mutex::scoped_lock lm (_mutex); + _colour_conversion = c; + } + + signal_changed (VideoContentProperty::COLOUR_CONVERSION); +} diff --git a/src/lib/video_content.h b/src/lib/video_content.h index 97ef6a9fa..72c72625b 100644 --- a/src/lib/video_content.h +++ b/src/lib/video_content.h @@ -21,6 +21,7 @@ #define DCPOMATIC_VIDEO_CONTENT_H #include "content.h" +#include "colour_conversion.h" class VideoExaminer; class Ratio; @@ -33,6 +34,7 @@ public: static int const VIDEO_FRAME_TYPE; static int const VIDEO_CROP; static int const VIDEO_RATIO; + static int const COLOUR_CONVERSION; }; class VideoContent : public virtual Content @@ -71,6 +73,8 @@ public: void set_top_crop (int); void set_bottom_crop (int); + void set_colour_conversion (ColourConversion); + VideoFrameType video_frame_type () const { boost::mutex::scoped_lock lm (_mutex); return _video_frame_type; @@ -88,6 +92,11 @@ public: return _ratio; } + ColourConversion colour_conversion () const { + boost::mutex::scoped_lock lm (_mutex); + return _colour_conversion; + } + libdcp::Size video_size_after_3d_split () const; protected: @@ -106,6 +115,7 @@ private: VideoFrameType _video_frame_type; Crop _crop; Ratio const * _ratio; + ColourConversion _colour_conversion; }; #endif diff --git a/src/tools/dcpomatic_cli.cc b/src/tools/dcpomatic_cli.cc index ff7ab6ffe..7695e1e94 100644 --- a/src/tools/dcpomatic_cli.cc +++ b/src/tools/dcpomatic_cli.cc @@ -116,7 +116,7 @@ main (int argc, char* argv[]) dcpomatic_setup (); if (no_remote) { - Config::instance()->set_servers (vector > ()); + Config::instance()->set_servers (vector ()); } cout << "DCP-o-matic " << dcpomatic_version << " git " << dcpomatic_git_commit; diff --git a/src/wx/colour_conversion_dialog.cc b/src/wx/colour_conversion_dialog.cc deleted file mode 100644 index 1a8008bfd..000000000 --- a/src/wx/colour_conversion_dialog.cc +++ /dev/null @@ -1,150 +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 -#include "lib/colour_conversion.h" -#include "wx_util.h" -#include "colour_conversion_dialog.h" - -using std::string; -using std::cout; -using boost::shared_ptr; -using boost::lexical_cast; - -ColourConversionDialog::ColourConversionDialog (wxWindow* parent, shared_ptr conversion) - : wxDialog (parent, wxID_ANY, _("Colour conversion")) - , _conversion (conversion) -{ - wxBoxSizer* overall_sizer = new wxBoxSizer (wxVERTICAL); - SetSizer (overall_sizer); - - wxGridBagSizer* table = new wxGridBagSizer (DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP); - overall_sizer->Add (table, 1, wxEXPAND | wxALL, DCPOMATIC_DIALOG_BORDER); - - int r = 0; - - add_label_to_grid_bag_sizer (table, this, _("Name"), true, wxGBPosition (r, 0)); - _name = new wxTextCtrl (this, wxID_ANY, wxT ("")); - table->Add (_name, wxGBPosition (r, 1), wxDefaultSpan, wxEXPAND); - ++r; - - add_label_to_grid_bag_sizer (table, this, _("Input gamma"), true, wxGBPosition (r, 0)); - _input_gamma = new wxSpinCtrlDouble (this); - table->Add (_input_gamma, wxGBPosition (r, 1)); - ++r; - - _input_gamma_linearised = new wxCheckBox (this, wxID_ANY, _("Linearise input gamma curve for low values")); - table->Add (_input_gamma_linearised, wxGBPosition (r, 0), wxGBSpan (1, 2)); - ++r; - - wxClientDC dc (parent); - wxSize size = dc.GetTextExtent (wxT ("0.123456789012")); - size.SetHeight (-1); - - wxTextValidator validator (wxFILTER_INCLUDE_CHAR_LIST); - wxArrayString list; - - wxString n (wxT ("0123456789.-")); - for (size_t i = 0; i < n.Length(); ++i) { - list.Add (n[i]); - } - - validator.SetIncludes (list); - - add_label_to_grid_bag_sizer (table, this, _("Matrix"), true, wxGBPosition (r, 0)); - wxFlexGridSizer* matrix_sizer = new wxFlexGridSizer (3, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP); - for (int x = 0; x < 3; ++x) { - for (int y = 0; y < 3; ++y) { - _matrix[x][y] = new wxTextCtrl (this, wxID_ANY, wxT (""), wxDefaultPosition, size, 0, validator); - matrix_sizer->Add (_matrix[x][y]); - } - } - table->Add (matrix_sizer, wxGBPosition (r, 1)); - ++r; - - add_label_to_grid_bag_sizer (table, this, _("Output gamma"), true, wxGBPosition (r, 0)); - wxBoxSizer* output_sizer = new wxBoxSizer (wxHORIZONTAL); - /* TRANSLATORS: this means the mathematical reciprocal operation, i.e. we are dividing 1 by the control that - comes after it. - */ - add_label_to_sizer (output_sizer, this, _("1 / "), false); - _output_gamma = new wxSpinCtrlDouble (this); - output_sizer->Add (_output_gamma); - table->Add (output_sizer, wxGBPosition (r, 1)); - ++r; - - wxSizer* buttons = CreateSeparatedButtonSizer (wxOK); - if (buttons) { - overall_sizer->Add (buttons, wxSizerFlags().Expand().DoubleBorder()); - } - - SetSizer (overall_sizer); - overall_sizer->Layout (); - overall_sizer->SetSizeHints (this); - - _input_gamma->SetRange(0.1, 4.0); - _input_gamma->SetDigits (1); - _input_gamma->SetIncrement (0.1); - _output_gamma->SetRange(0.1, 4.0); - _output_gamma->SetDigits (1); - _output_gamma->SetIncrement (0.1); - - _name->SetValue (std_to_wx (conversion->name)); - _input_gamma->SetValue (conversion->input_gamma); - _input_gamma_linearised->SetValue (conversion->input_gamma_linearised); - for (int i = 0; i < 3; ++i) { - for (int j = 0; j < 3; ++j) { - _matrix[i][j]->SetValue (std_to_wx (lexical_cast (conversion->matrix(i, j)))); - } - } - _output_gamma->SetValue (conversion->output_gamma); - - _name->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&ColourConversionDialog::changed, this)); - _input_gamma->Bind (wxEVT_COMMAND_SPINCTRLDOUBLE_UPDATED, boost::bind (&ColourConversionDialog::changed, this)); - _input_gamma_linearised->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&ColourConversionDialog::changed, this)); - _output_gamma->Bind (wxEVT_COMMAND_SPINCTRLDOUBLE_UPDATED, boost::bind (&ColourConversionDialog::changed, this)); - for (int i = 0; i < 3; ++i) { - for (int j = 0; j < 3; ++j) { - _matrix[i][j]->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&ColourConversionDialog::changed, this)); - } - } -} - -void -ColourConversionDialog::changed () -{ - _conversion->name = wx_to_std (_name->GetValue ()); - _conversion->input_gamma = _input_gamma->GetValue (); - _conversion->input_gamma_linearised = _input_gamma_linearised->GetValue (); - - for (int i = 0; i < 3; ++i) { - for (int j = 0; j < 3; ++j) { - string const v = wx_to_std (_matrix[i][j]->GetValue ()); - if (v.empty ()) { - _conversion->matrix (i, j) = 0; - } else { - _conversion->matrix (i, j) = lexical_cast (v); - } - } - } - _conversion->output_gamma = _output_gamma->GetValue (); -} - diff --git a/src/wx/colour_conversion_dialog.h b/src/wx/colour_conversion_dialog.h deleted file mode 100644 index 8da6df100..000000000 --- a/src/wx/colour_conversion_dialog.h +++ /dev/null @@ -1,39 +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 - -class wxSpinCtrlDouble; -class ColourConversion; - -class ColourConversionDialog : public wxDialog -{ -public: - ColourConversionDialog (wxWindow *, boost::shared_ptr); - -private: - void changed (); - - boost::shared_ptr _conversion; - wxTextCtrl* _name; - wxSpinCtrlDouble* _input_gamma; - wxCheckBox* _input_gamma_linearised; - wxTextCtrl* _matrix[3][3]; - wxSpinCtrlDouble* _output_gamma; -}; diff --git a/src/wx/colour_conversion_editor.cc b/src/wx/colour_conversion_editor.cc new file mode 100644 index 000000000..091028dcd --- /dev/null +++ b/src/wx/colour_conversion_editor.cc @@ -0,0 +1,152 @@ +/* + 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 +#include "lib/colour_conversion.h" +#include "wx_util.h" +#include "colour_conversion_editor.h" + +using std::string; +using std::cout; +using std::stringstream; +using boost::shared_ptr; +using boost::lexical_cast; + +ColourConversionEditor::ColourConversionEditor (wxWindow* parent) + : wxPanel (parent, wxID_ANY) +{ + wxBoxSizer* overall_sizer = new wxBoxSizer (wxVERTICAL); + SetSizer (overall_sizer); + + wxGridBagSizer* table = new wxGridBagSizer (DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP); + overall_sizer->Add (table, 1, wxEXPAND | wxALL, DCPOMATIC_DIALOG_BORDER); + + int r = 0; + + add_label_to_grid_bag_sizer (table, this, _("Input gamma"), true, wxGBPosition (r, 0)); + _input_gamma = new wxSpinCtrlDouble (this); + table->Add (_input_gamma, wxGBPosition (r, 1)); + ++r; + + _input_gamma_linearised = new wxCheckBox (this, wxID_ANY, _("Linearise input gamma curve for low values")); + table->Add (_input_gamma_linearised, wxGBPosition (r, 0), wxGBSpan (1, 2)); + ++r; + + wxClientDC dc (parent); + wxSize size = dc.GetTextExtent (wxT ("-0.123456789012345678")); + size.SetHeight (-1); + + wxTextValidator validator (wxFILTER_INCLUDE_CHAR_LIST); + wxArrayString list; + + wxString n (wxT ("0123456789.-")); + for (size_t i = 0; i < n.Length(); ++i) { + list.Add (n[i]); + } + + validator.SetIncludes (list); + + add_label_to_grid_bag_sizer (table, this, _("Matrix"), true, wxGBPosition (r, 0)); + wxFlexGridSizer* matrix_sizer = new wxFlexGridSizer (3, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP); + for (int i = 0; i < 3; ++i) { + for (int j = 0; j < 3; ++j) { + _matrix[i][j] = new wxTextCtrl (this, wxID_ANY, wxT (""), wxDefaultPosition, size, 0, validator); + matrix_sizer->Add (_matrix[i][j]); + } + } + table->Add (matrix_sizer, wxGBPosition (r, 1)); + ++r; + + add_label_to_grid_bag_sizer (table, this, _("Output gamma"), true, wxGBPosition (r, 0)); + wxBoxSizer* output_sizer = new wxBoxSizer (wxHORIZONTAL); + /* TRANSLATORS: this means the mathematical reciprocal operation, i.e. we are dividing 1 by the control that + comes after it. + */ + add_label_to_sizer (output_sizer, this, _("1 / "), false); + _output_gamma = new wxSpinCtrlDouble (this); + output_sizer->Add (_output_gamma); + table->Add (output_sizer, wxGBPosition (r, 1)); + ++r; + + _input_gamma->SetRange(0.1, 4.0); + _input_gamma->SetDigits (1); + _input_gamma->SetIncrement (0.1); + _output_gamma->SetRange(0.1, 4.0); + _output_gamma->SetDigits (1); + _output_gamma->SetIncrement (0.1); + + _input_gamma->Bind (wxEVT_COMMAND_SPINCTRLDOUBLE_UPDATED, boost::bind (&ColourConversionEditor::changed, this)); + _input_gamma_linearised->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&ColourConversionEditor::changed, this)); + for (int i = 0; i < 3; ++i) { + for (int j = 0; j < 3; ++j) { + _matrix[i][j]->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&ColourConversionEditor::changed, this)); + } + } + _output_gamma->Bind (wxEVT_COMMAND_SPINCTRLDOUBLE_UPDATED, boost::bind (&ColourConversionEditor::changed, this)); +} + +void +ColourConversionEditor::set (ColourConversion conversion) +{ + _input_gamma->SetValue (conversion.input_gamma); + _input_gamma_linearised->SetValue (conversion.input_gamma_linearised); + for (int i = 0; i < 3; ++i) { + for (int j = 0; j < 3; ++j) { + stringstream s; + s.setf (std::ios::fixed, std::ios::floatfield); + s.precision (14); + s << conversion.matrix (i, j); + _matrix[i][j]->SetValue (std_to_wx (s.str ())); + } + } + _output_gamma->SetValue (conversion.output_gamma); +} + +ColourConversion +ColourConversionEditor::get () const +{ + ColourConversion conversion; + + conversion.input_gamma = _input_gamma->GetValue (); + conversion.input_gamma_linearised = _input_gamma_linearised->GetValue (); + + for (int i = 0; i < 3; ++i) { + for (int j = 0; j < 3; ++j) { + string const v = wx_to_std (_matrix[i][j]->GetValue ()); + if (v.empty ()) { + conversion.matrix (i, j) = 0; + } else { + conversion.matrix (i, j) = lexical_cast (v); + } + } + } + + conversion.output_gamma = _output_gamma->GetValue (); + + return conversion; +} + +void +ColourConversionEditor::changed () +{ + Changed (); +} + diff --git a/src/wx/colour_conversion_editor.h b/src/wx/colour_conversion_editor.h new file mode 100644 index 000000000..8567cac22 --- /dev/null +++ b/src/wx/colour_conversion_editor.h @@ -0,0 +1,48 @@ +/* + 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. + +*/ + +#ifndef DCPOMATIC_COLOUR_CONVERSION_EDITOR_H +#define DCPOMATIC_COLOUR_CONVERSION_EDITOR_H + +#include +#include + +class wxSpinCtrlDouble; +class ColourConversion; + +class ColourConversionEditor : public wxPanel +{ +public: + ColourConversionEditor (wxWindow *); + + void set (ColourConversion); + ColourConversion get () const; + + boost::signals2::signal Changed; + +private: + void changed (); + + wxSpinCtrlDouble* _input_gamma; + wxCheckBox* _input_gamma_linearised; + wxTextCtrl* _matrix[3][3]; + wxSpinCtrlDouble* _output_gamma; +}; + +#endif diff --git a/src/wx/config_dialog.cc b/src/wx/config_dialog.cc index 66f0cd186..7f1efa52f 100644 --- a/src/wx/config_dialog.cc +++ b/src/wx/config_dialog.cc @@ -40,7 +40,7 @@ #include "server_dialog.h" #include "dir_picker_ctrl.h" #include "dci_metadata_dialog.h" -#include "colour_conversion_dialog.h" +#include "preset_colour_conversion_dialog.h" using std::vector; using std::string; @@ -280,13 +280,13 @@ ConfigDialog::make_metadata_panel () } static std::string -server_column (shared_ptr s, int c) +server_column (ServerDescription s, int c) { switch (c) { case 0: - return s->host_name (); + return s.host_name (); case 1: - return lexical_cast (s->threads ()); + return lexical_cast (s.threads ()); } return ""; @@ -434,9 +434,9 @@ ConfigDialog::default_j2k_bandwidth_changed () } static std::string -colour_conversion_column (shared_ptr c) +colour_conversion_column (PresetColourConversion c) { - return c->name; + return c.name; } void @@ -444,7 +444,7 @@ ConfigDialog::make_colour_conversions_panel () { vector columns; columns.push_back (wx_to_std (_("Name"))); - _colour_conversions_panel = new EditableList ( + _colour_conversions_panel = new EditableList ( _notebook, columns, boost::bind (&Config::colour_conversions, Config::instance()), diff --git a/src/wx/config_dialog.h b/src/wx/config_dialog.h index 60d9229c4..82c4ee2a0 100644 --- a/src/wx/config_dialog.h +++ b/src/wx/config_dialog.h @@ -31,8 +31,8 @@ class DirPickerCtrl; class wxNotebook; class ServerDescription; -class ColourConversion; -class ColourConversionDialog; +class PresetColourConversion; +class PresetColourConversionDialog; class ServerDialog; /** @class ConfigDialog @@ -71,7 +71,7 @@ private: wxNotebook* _notebook; wxPanel* _misc_panel; wxPanel* _tms_panel; - EditableList* _colour_conversions_panel; + EditableList* _colour_conversions_panel; EditableList* _servers_panel; wxPanel* _metadata_panel; wxCheckBox* _set_language; diff --git a/src/wx/content_colour_conversion_dialog.cc b/src/wx/content_colour_conversion_dialog.cc new file mode 100644 index 000000000..8fca090ad --- /dev/null +++ b/src/wx/content_colour_conversion_dialog.cc @@ -0,0 +1,121 @@ +/* + 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 "lib/colour_conversion.h" +#include "lib/config.h" +#include "wx_util.h" +#include "content_colour_conversion_dialog.h" +#include "colour_conversion_editor.h" + +using std::string; +using std::vector; +using std::cout; +using boost::optional; + +ContentColourConversionDialog::ContentColourConversionDialog (wxWindow* parent) + : wxDialog (parent, wxID_ANY, _("Colour conversion")) + , _editor (new ColourConversionEditor (this)) + , _setting (false) +{ + wxBoxSizer* overall_sizer = new wxBoxSizer (wxVERTICAL); + SetSizer (overall_sizer); + + wxFlexGridSizer* table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP); + _preset_check = new wxCheckBox (this, wxID_ANY, _("Use preset")); + table->Add (_preset_check, 0, wxALIGN_CENTER_VERTICAL); + _preset_choice = new wxChoice (this, wxID_ANY); + table->Add (_preset_choice); + + overall_sizer->Add (table, 1, wxEXPAND | wxALL, DCPOMATIC_DIALOG_BORDER); + overall_sizer->Add (new wxStaticLine (this, wxID_ANY)); + overall_sizer->Add (_editor); + + wxSizer* buttons = CreateSeparatedButtonSizer (wxOK); + if (buttons) { + overall_sizer->Add (buttons, wxSizerFlags().Expand().DoubleBorder()); + } + + overall_sizer->Layout (); + overall_sizer->SetSizeHints (this); + + _preset_check->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&ContentColourConversionDialog::preset_check_clicked, this)); + _preset_choice->Bind (wxEVT_COMMAND_CHOICE_SELECTED, boost::bind (&ContentColourConversionDialog::preset_choice_changed, this)); + + _editor->Changed.connect (boost::bind (&ContentColourConversionDialog::check_for_preset, this)); + + vector presets = Config::instance()->colour_conversions (); + for (vector::const_iterator i = presets.begin(); i != presets.end(); ++i) { + _preset_choice->Append (std_to_wx (i->name)); + } +} + +ColourConversion +ContentColourConversionDialog::get () const +{ + return _editor->get (); +} + +void +ContentColourConversionDialog::set (ColourConversion c) +{ + _setting = true; + _editor->set (c); + _setting = false; + + check_for_preset (); +} + +void +ContentColourConversionDialog::check_for_preset () +{ + if (_setting) { + return; + } + + optional preset = _editor->get().preset (); + + _preset_check->SetValue (preset); + _preset_choice->Enable (preset); + _preset_choice->SetSelection (preset.get_value_or (-1)); +} + +void +ContentColourConversionDialog::preset_check_clicked () +{ + if (_preset_check->GetValue ()) { + _preset_choice->SetSelection (0); + preset_choice_changed (); + } else { + _preset_choice->SetSelection (-1); + _preset_choice->Enable (false); + } +} + +void +ContentColourConversionDialog::preset_choice_changed () +{ + vector presets = Config::instance()->colour_conversions (); + int const s = _preset_choice->GetSelection(); + if (s != -1) { + set (presets[s].conversion); + } +} + + diff --git a/src/wx/content_colour_conversion_dialog.h b/src/wx/content_colour_conversion_dialog.h new file mode 100644 index 000000000..e6069f117 --- /dev/null +++ b/src/wx/content_colour_conversion_dialog.h @@ -0,0 +1,41 @@ +/* + 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 + +class ColourConversionEditor; + +class ContentColourConversionDialog : public wxDialog +{ +public: + ContentColourConversionDialog (wxWindow *); + + void set (ColourConversion); + ColourConversion get () const; + +private: + void check_for_preset (); + void preset_check_clicked (); + void preset_choice_changed (); + + wxCheckBox* _preset_check; + wxChoice* _preset_choice; + ColourConversionEditor* _editor; + bool _setting; +}; diff --git a/src/wx/editable_list.h b/src/wx/editable_list.h index 32cc326b6..5eb46e80d 100644 --- a/src/wx/editable_list.h +++ b/src/wx/editable_list.h @@ -26,9 +26,9 @@ public: EditableList ( wxWindow* parent, std::vector columns, - boost::function > ()> get, - boost::function >)> set, - boost::function, int)> column + boost::function ()> get, + boost::function)> set, + boost::function column ) : wxPanel (parent) , _get (get) @@ -66,8 +66,8 @@ public: table->Add (s, 0); } - std::vector > current = _get (); - for (typename std::vector >::iterator i = current.begin (); i != current.end(); ++i) { + std::vector current = _get (); + for (typename std::vector::iterator i = current.begin (); i != current.end(); ++i) { add_to_control (*i); } @@ -77,10 +77,14 @@ public: _list->Bind (wxEVT_COMMAND_LIST_ITEM_SELECTED, boost::bind (&EditableList::selection_changed, this)); _list->Bind (wxEVT_COMMAND_LIST_ITEM_DESELECTED, boost::bind (&EditableList::selection_changed, this)); + _list->Bind (wxEVT_SIZE, boost::bind (&EditableList::resized, this, _1)); selection_changed (); + } - void add_to_control (boost::shared_ptr item) +private: + + void add_to_control (T item) { wxListItem list_item; int const n = _list->GetItemCount (); @@ -101,15 +105,18 @@ public: void add_clicked () { - boost::shared_ptr new_item (new T); - S* dialog = new S (this, new_item); + T new_item; + S* dialog = new S (this); + dialog->set (new_item); dialog->ShowModal (); - dialog->Destroy (); - add_to_control (new_item); - std::vector > all = _get (); - all.push_back (new_item); + add_to_control (dialog->get ()); + + std::vector all = _get (); + all.push_back (dialog->get ()); _set (all); + + dialog->Destroy (); } void edit_clicked () @@ -119,13 +126,15 @@ public: return; } - std::vector > all = _get (); + std::vector all = _get (); assert (item >= 0 && item < int (all.size ())); - S* dialog = new S (this, all[item]); + S* dialog = new S (this); + dialog->set (all[item]); dialog->ShowModal (); + all[item] = dialog->get (); dialog->Destroy (); - + for (int i = 0; i < _columns; ++i) { _list->SetItem (item, i, std_to_wx (_column (all[item], i))); } @@ -138,16 +147,24 @@ public: _list->DeleteItem (i); } - std::vector > all = _get (); + std::vector all = _get (); all.erase (all.begin() + i); _set (all); } -private: - boost::function > ()> _get; - boost::function >)> _set; + void resized (wxSizeEvent& ev) + { + int const w = GetSize().GetWidth() / _columns; + for (int i = 0; i < _columns; ++i) { + _list->SetColumnWidth (i, w); + } + ev.Skip (); + } + + boost::function ()> _get; + boost::function )> _set; int _columns; - boost::function, int)> _column; + boost::function _column; wxButton* _add; wxButton* _edit; diff --git a/src/wx/film_editor.cc b/src/wx/film_editor.cc index 812da88bf..28c315a96 100644 --- a/src/wx/film_editor.cc +++ b/src/wx/film_editor.cc @@ -741,6 +741,7 @@ FilmEditor::content_selection_changed () film_content_changed (s, VideoContentProperty::VIDEO_CROP); film_content_changed (s, VideoContentProperty::VIDEO_RATIO); film_content_changed (s, VideoContentProperty::VIDEO_FRAME_TYPE); + film_content_changed (s, VideoContentProperty::COLOUR_CONVERSION); film_content_changed (s, AudioContentProperty::AUDIO_GAIN); film_content_changed (s, AudioContentProperty::AUDIO_DELAY); film_content_changed (s, AudioContentProperty::AUDIO_MAPPING); diff --git a/src/wx/filter_dialog.cc b/src/wx/filter_dialog.cc index 2abe53026..13907ae0c 100644 --- a/src/wx/filter_dialog.cc +++ b/src/wx/filter_dialog.cc @@ -23,14 +23,14 @@ #include "lib/film.h" #include "filter_dialog.h" -#include "filter_view.h" +#include "filter_editor.h" using namespace std; using boost::bind; FilterDialog::FilterDialog (wxWindow* parent, vector const & f) : wxDialog (parent, wxID_ANY, wxString (_("Filters"))) - , _filters (new FilterView (this, f)) + , _filters (new FilterEditor (this, f)) { wxBoxSizer* sizer = new wxBoxSizer (wxVERTICAL); sizer->Add (_filters, 1, wxEXPAND | wxALL, 6); diff --git a/src/wx/filter_dialog.h b/src/wx/filter_dialog.h index 6f8b1dd1c..d54e6f2e4 100644 --- a/src/wx/filter_dialog.h +++ b/src/wx/filter_dialog.h @@ -25,7 +25,7 @@ #include class Film; -class FilterView; +class FilterEditor; class Filter; /** @class FilterDialog @@ -41,5 +41,5 @@ public: private: void active_changed (); - FilterView* _filters; + FilterEditor* _filters; }; diff --git a/src/wx/filter_editor.cc b/src/wx/filter_editor.cc new file mode 100644 index 000000000..4dd18004b --- /dev/null +++ b/src/wx/filter_editor.cc @@ -0,0 +1,92 @@ +/* + 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/filter_editor.cc + * @brief A panel to select FFmpeg filters. + */ + +#include +#include +#include "lib/filter.h" +#include "filter_editor.h" +#include "wx_util.h" + +using namespace std; + +FilterEditor::FilterEditor (wxWindow* parent, vector const & active) + : wxPanel (parent) +{ + wxBoxSizer* sizer = new wxBoxSizer (wxVERTICAL); + SetSizer (sizer); + + vector filters = Filter::all (); + + typedef map > CategoryMap; + CategoryMap categories; + + for (vector::iterator i = filters.begin(); i != filters.end(); ++i) { + CategoryMap::iterator j = categories.find ((*i)->category ()); + if (j == categories.end ()) { + list c; + c.push_back (*i); + categories[(*i)->category()] = c; + } else { + j->second.push_back (*i); + } + } + + for (CategoryMap::iterator i = categories.begin(); i != categories.end(); ++i) { + + wxStaticText* c = new wxStaticText (this, wxID_ANY, std_to_wx (i->first)); + wxFont font = c->GetFont(); + font.SetWeight(wxFONTWEIGHT_BOLD); + c->SetFont(font); + sizer->Add (c); + + for (list::iterator j = i->second.begin(); j != i->second.end(); ++j) { + wxCheckBox* b = new wxCheckBox (this, wxID_ANY, std_to_wx ((*j)->name ())); + bool const a = find (active.begin(), active.end(), *j) != active.end (); + b->SetValue (a); + _filters[*j] = b; + b->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&FilterEditor::filter_toggled, this)); + sizer->Add (b); + } + + sizer->AddSpacer (6); + } +} + +void +FilterEditor::filter_toggled () +{ + ActiveChanged (); +} + +vector +FilterEditor::active () const +{ + vector active; + for (map::const_iterator i = _filters.begin(); i != _filters.end(); ++i) { + if (i->second->IsChecked ()) { + active.push_back (i->first); + } + } + + return active; +} diff --git a/src/wx/filter_editor.h b/src/wx/filter_editor.h new file mode 100644 index 000000000..4e1d682d5 --- /dev/null +++ b/src/wx/filter_editor.h @@ -0,0 +1,47 @@ +/* + 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/filter_editor.h + * @brief A panel to select FFmpeg filters. + */ + +#include +#include +#include +#include + +class Filter; + +/** @class FilterEditor + * @brief A panel to select FFmpeg filters. + */ +class FilterEditor : public wxPanel +{ +public: + FilterEditor (wxWindow *, std::vector const &); + + std::vector active () const; + + boost::signals2::signal ActiveChanged; + +private: + void filter_toggled (); + + std::map _filters; +}; diff --git a/src/wx/filter_view.cc b/src/wx/filter_view.cc deleted file mode 100644 index 757daf3fa..000000000 --- a/src/wx/filter_view.cc +++ /dev/null @@ -1,92 +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/filter_view.cc - * @brief A panel to select FFmpeg filters. - */ - -#include -#include -#include "lib/filter.h" -#include "filter_view.h" -#include "wx_util.h" - -using namespace std; - -FilterView::FilterView (wxWindow* parent, vector const & active) - : wxPanel (parent) -{ - wxBoxSizer* sizer = new wxBoxSizer (wxVERTICAL); - SetSizer (sizer); - - vector filters = Filter::all (); - - typedef map > CategoryMap; - CategoryMap categories; - - for (vector::iterator i = filters.begin(); i != filters.end(); ++i) { - CategoryMap::iterator j = categories.find ((*i)->category ()); - if (j == categories.end ()) { - list c; - c.push_back (*i); - categories[(*i)->category()] = c; - } else { - j->second.push_back (*i); - } - } - - for (CategoryMap::iterator i = categories.begin(); i != categories.end(); ++i) { - - wxStaticText* c = new wxStaticText (this, wxID_ANY, std_to_wx (i->first)); - wxFont font = c->GetFont(); - font.SetWeight(wxFONTWEIGHT_BOLD); - c->SetFont(font); - sizer->Add (c); - - for (list::iterator j = i->second.begin(); j != i->second.end(); ++j) { - wxCheckBox* b = new wxCheckBox (this, wxID_ANY, std_to_wx ((*j)->name ())); - bool const a = find (active.begin(), active.end(), *j) != active.end (); - b->SetValue (a); - _filters[*j] = b; - b->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&FilterView::filter_toggled, this)); - sizer->Add (b); - } - - sizer->AddSpacer (6); - } -} - -void -FilterView::filter_toggled () -{ - ActiveChanged (); -} - -vector -FilterView::active () const -{ - vector active; - for (map::const_iterator i = _filters.begin(); i != _filters.end(); ++i) { - if (i->second->IsChecked ()) { - active.push_back (i->first); - } - } - - return active; -} diff --git a/src/wx/filter_view.h b/src/wx/filter_view.h deleted file mode 100644 index 7fbef84bf..000000000 --- a/src/wx/filter_view.h +++ /dev/null @@ -1,47 +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/filter_view.h - * @brief A panel to select FFmpeg filters. - */ - -#include -#include -#include -#include - -class Filter; - -/** @class FilterView - * @brief A panel to select FFmpeg filters. - */ -class FilterView : public wxPanel -{ -public: - FilterView (wxWindow *, std::vector const &); - - std::vector active () const; - - boost::signals2::signal ActiveChanged; - -private: - void filter_toggled (); - - std::map _filters; -}; diff --git a/src/wx/preset_colour_conversion_dialog.cc b/src/wx/preset_colour_conversion_dialog.cc new file mode 100644 index 000000000..8c4a6dbcf --- /dev/null +++ b/src/wx/preset_colour_conversion_dialog.cc @@ -0,0 +1,68 @@ +/* + 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 "lib/colour_conversion.h" +#include "wx_util.h" +#include "preset_colour_conversion_dialog.h" +#include "colour_conversion_editor.h" + +using std::string; +using std::cout; + +PresetColourConversionDialog::PresetColourConversionDialog (wxWindow* parent) + : wxDialog (parent, wxID_ANY, _("Colour conversion")) + , _editor (new ColourConversionEditor (this)) +{ + wxBoxSizer* overall_sizer = new wxBoxSizer (wxVERTICAL); + SetSizer (overall_sizer); + + wxFlexGridSizer* table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP); + add_label_to_sizer (table, this, _("Name"), true); + _name = new wxTextCtrl (this, wxID_ANY, wxT ("")); + table->Add (_name); + + overall_sizer->Add (table, 1, wxEXPAND | wxALL, DCPOMATIC_DIALOG_BORDER); + overall_sizer->Add (new wxStaticLine (this, wxID_ANY)); + overall_sizer->Add (_editor); + + wxSizer* buttons = CreateSeparatedButtonSizer (wxOK); + if (buttons) { + overall_sizer->Add (buttons, wxSizerFlags().Expand().DoubleBorder()); + } + + overall_sizer->Layout (); + overall_sizer->SetSizeHints (this); +} + +PresetColourConversion +PresetColourConversionDialog::get () const +{ + PresetColourConversion pc; + pc.name = wx_to_std (_name->GetValue ()); + pc.conversion = _editor->get (); + return pc; +} + +void +PresetColourConversionDialog::set (PresetColourConversion c) +{ + _name->SetValue (std_to_wx (c.name)); + _editor->set (c.conversion); +} diff --git a/src/wx/preset_colour_conversion_dialog.h b/src/wx/preset_colour_conversion_dialog.h new file mode 100644 index 000000000..4e612398c --- /dev/null +++ b/src/wx/preset_colour_conversion_dialog.h @@ -0,0 +1,35 @@ +/* + 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 + +class ColourConversionEditor; + +class PresetColourConversionDialog : public wxDialog +{ +public: + PresetColourConversionDialog (wxWindow *); + + void set (PresetColourConversion); + PresetColourConversion get () const; + +private: + wxTextCtrl* _name; + ColourConversionEditor* _editor; +}; diff --git a/src/wx/server_dialog.cc b/src/wx/server_dialog.cc index a0f1f04ae..31b3ce5dc 100644 --- a/src/wx/server_dialog.cc +++ b/src/wx/server_dialog.cc @@ -23,15 +23,9 @@ using boost::shared_ptr; -ServerDialog::ServerDialog (wxWindow* parent, shared_ptr server) +ServerDialog::ServerDialog (wxWindow* parent) : wxDialog (parent, wxID_ANY, _("Server")) { - if (server) { - _server = server; - } else { - _server.reset (new ServerDescription (wx_to_std (N_("localhost")), 1)); - } - wxFlexGridSizer* table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP); table->AddGrowableCol (1, 1); @@ -43,12 +37,7 @@ ServerDialog::ServerDialog (wxWindow* parent, shared_ptr serv _threads = new wxSpinCtrl (this, wxID_ANY); table->Add (_threads, 1, wxEXPAND); - _host->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&ServerDialog::host_changed, this)); _threads->SetRange (0, 256); - _threads->Bind (wxEVT_COMMAND_SPINCTRL_UPDATED, boost::bind (&ServerDialog::threads_changed, this)); - - _host->SetValue (std_to_wx (_server->host_name ())); - _threads->SetValue (_server->threads ()); wxBoxSizer* overall_sizer = new wxBoxSizer (wxVERTICAL); overall_sizer->Add (table, 1, wxEXPAND | wxALL, 6); @@ -64,20 +53,18 @@ ServerDialog::ServerDialog (wxWindow* parent, shared_ptr serv } void -ServerDialog::host_changed () -{ - _server->set_host_name (wx_to_std (_host->GetValue ())); -} - -void -ServerDialog::threads_changed () +ServerDialog::set (ServerDescription server) { - _server->set_threads (_threads->GetValue ()); + _host->SetValue (std_to_wx (server.host_name ())); + _threads->SetValue (server.threads ()); } -shared_ptr -ServerDialog::server () const +ServerDescription +ServerDialog::get () const { - return _server; + ServerDescription server; + server.set_host_name (wx_to_std (_host->GetValue ())); + server.set_threads (_threads->GetValue ()); + return server; } diff --git a/src/wx/server_dialog.h b/src/wx/server_dialog.h index 3f1fa1f73..a6f48fe7b 100644 --- a/src/wx/server_dialog.h +++ b/src/wx/server_dialog.h @@ -25,15 +25,12 @@ class ServerDescription; class ServerDialog : public wxDialog { public: - ServerDialog (wxWindow *, boost::shared_ptr); + ServerDialog (wxWindow *); - boost::shared_ptr server () const; + void set (ServerDescription); + ServerDescription get () const; private: - void host_changed (); - void threads_changed (); - - boost::shared_ptr _server; wxTextCtrl* _host; wxSpinCtrl* _threads; }; diff --git a/src/wx/video_panel.cc b/src/wx/video_panel.cc index 5ba06b12d..bb8476d63 100644 --- a/src/wx/video_panel.cc +++ b/src/wx/video_panel.cc @@ -27,6 +27,7 @@ #include "video_panel.h" #include "wx_util.h" #include "film_editor.h" +#include "content_colour_conversion_dialog.h" using std::vector; using std::string; @@ -36,6 +37,7 @@ using std::list; using boost::shared_ptr; using boost::dynamic_pointer_cast; using boost::bind; +using boost::optional; VideoPanel::VideoPanel (FilmEditor* e) : FilmEditorPanel (e, _("Video")) @@ -78,17 +80,34 @@ VideoPanel::VideoPanel (FilmEditor* e) { add_label_to_grid_bag_sizer (grid, this, _("Filters"), true, wxGBPosition (r, 0)); wxSizer* s = new wxBoxSizer (wxHORIZONTAL); - _filters = new wxStaticText (this, wxID_ANY, _("None")); + + wxClientDC dc (this); + wxSize size = dc.GetTextExtent (wxT ("A quite long name")); + size.SetHeight (-1); + + _filters = new wxStaticText (this, wxID_ANY, _("None"), wxDefaultPosition, size); s->Add (_filters, 1, wxEXPAND | wxALIGN_CENTER_VERTICAL | wxTOP | wxBOTTOM | wxRIGHT, 6); _filters_button = new wxButton (this, wxID_ANY, _("Edit...")); s->Add (_filters_button, 0, wxALIGN_CENTER_VERTICAL); grid->Add (s, wxGBPosition (r, 1), wxDefaultSpan, wxALIGN_CENTER_VERTICAL); } ++r; + + { + add_label_to_grid_bag_sizer (grid, this, _("Colour conversion"), true, wxGBPosition (r, 0)); + wxSizer* s = new wxBoxSizer (wxHORIZONTAL); - add_label_to_grid_bag_sizer (grid, this, _("Colour conversion"), true, wxGBPosition (r, 0)); - _colour_conversion = new wxChoice (this, wxID_ANY); - grid->Add (_colour_conversion, wxGBPosition (r, 1)); + wxClientDC dc (this); + wxSize size = dc.GetTextExtent (wxT ("A quite long name")); + size.SetHeight (-1); + + _colour_conversion = new wxStaticText (this, wxID_ANY, wxT (""), wxDefaultPosition, size); + + s->Add (_colour_conversion, 1, wxEXPAND | wxALIGN_CENTER_VERTICAL | wxTOP | wxBOTTOM | wxRIGHT, 6); + _colour_conversion_button = new wxButton (this, wxID_ANY, _("Edit...")); + s->Add (_colour_conversion_button, 0, wxALIGN_CENTER_VERTICAL); + grid->Add (s, wxGBPosition (r, 1), wxDefaultSpan, wxALIGN_CENTER_VERTICAL); + } ++r; _description = new wxStaticText (this, wxID_ANY, wxT ("\n \n \n \n \n"), wxDefaultPosition, wxDefaultSize); @@ -113,16 +132,14 @@ VideoPanel::VideoPanel (FilmEditor* e) _frame_type->Append (_("2D")); _frame_type->Append (_("3D left/right")); - setup_colour_conversions (); - - _frame_type->Bind (wxEVT_COMMAND_CHOICE_SELECTED, boost::bind (&VideoPanel::frame_type_changed, this)); - _left_crop->Bind (wxEVT_COMMAND_SPINCTRL_UPDATED, boost::bind (&VideoPanel::left_crop_changed, this)); - _right_crop->Bind (wxEVT_COMMAND_SPINCTRL_UPDATED, boost::bind (&VideoPanel::right_crop_changed, this)); - _top_crop->Bind (wxEVT_COMMAND_SPINCTRL_UPDATED, boost::bind (&VideoPanel::top_crop_changed, this)); - _bottom_crop->Bind (wxEVT_COMMAND_SPINCTRL_UPDATED, boost::bind (&VideoPanel::bottom_crop_changed, this)); - _ratio->Bind (wxEVT_COMMAND_CHOICE_SELECTED, boost::bind (&VideoPanel::ratio_changed, this)); - _filters_button->Bind (wxEVT_COMMAND_BUTTON_CLICKED, boost::bind (&VideoPanel::edit_filters_clicked, this)); - _colour_conversion->Bind (wxEVT_COMMAND_CHOICE_SELECTED, boost::bind (&VideoPanel::colour_conversion_changed, this)); + _frame_type->Bind (wxEVT_COMMAND_CHOICE_SELECTED, boost::bind (&VideoPanel::frame_type_changed, this)); + _left_crop->Bind (wxEVT_COMMAND_SPINCTRL_UPDATED, boost::bind (&VideoPanel::left_crop_changed, this)); + _right_crop->Bind (wxEVT_COMMAND_SPINCTRL_UPDATED, boost::bind (&VideoPanel::right_crop_changed, this)); + _top_crop->Bind (wxEVT_COMMAND_SPINCTRL_UPDATED, boost::bind (&VideoPanel::top_crop_changed, this)); + _bottom_crop->Bind (wxEVT_COMMAND_SPINCTRL_UPDATED, boost::bind (&VideoPanel::bottom_crop_changed, this)); + _ratio->Bind (wxEVT_COMMAND_CHOICE_SELECTED, boost::bind (&VideoPanel::ratio_changed, this)); + _filters_button->Bind (wxEVT_COMMAND_BUTTON_CLICKED, boost::bind (&VideoPanel::edit_filters_clicked, this)); + _colour_conversion_button->Bind (wxEVT_COMMAND_BUTTON_CLICKED, boost::bind (&VideoPanel::edit_colour_conversion_clicked, this)); } @@ -223,6 +240,10 @@ VideoPanel::film_content_changed (shared_ptr c, int property) setup_description (); } else if (property == VideoContentProperty::VIDEO_FRAME_RATE) { setup_description (); + } else if (property == VideoContentProperty::COLOUR_CONVERSION) { + optional preset = vc ? vc->colour_conversion().preset () : optional (); + vector cc = Config::instance()->colour_conversions (); + _colour_conversion->SetLabel (preset ? std_to_wx (cc[preset.get()].name) : _("Custom")); } else if (property == FFmpegContentProperty::FILTERS) { if (fc) { pair p = Filter::ffmpeg_strings (fc->filters ()); @@ -355,16 +376,18 @@ VideoPanel::frame_type_changed () } void -VideoPanel::setup_colour_conversions () +VideoPanel::edit_colour_conversion_clicked () { - vector > cc = Config::instance()->colour_conversions (); - for (vector >::iterator i = cc.begin(); i != cc.end(); ++i) { - _colour_conversion->Append (std_to_wx ((*i)->name)); + shared_ptr vc = _editor->selected_video_content (); + if (!vc) { + return; } -} -void -VideoPanel::colour_conversion_changed () -{ + ColourConversion conversion = vc->colour_conversion (); + ContentColourConversionDialog* d = new ContentColourConversionDialog (this); + d->set (conversion); + d->ShowModal (); + vc->set_colour_conversion (d->get ()); + d->Destroy (); } diff --git a/src/wx/video_panel.h b/src/wx/video_panel.h index 62332a052..2ecf3c87f 100644 --- a/src/wx/video_panel.h +++ b/src/wx/video_panel.h @@ -41,10 +41,9 @@ private: void edit_filters_clicked (); void ratio_changed (); void frame_type_changed (); - void colour_conversion_changed (); + void edit_colour_conversion_clicked (); void setup_description (); - void setup_colour_conversions (); wxChoice* _frame_type; wxSpinCtrl* _left_crop; @@ -56,5 +55,6 @@ private: wxStaticText* _description; wxStaticText* _filters; wxButton* _filters_button; - wxChoice* _colour_conversion; + wxStaticText* _colour_conversion; + wxButton* _colour_conversion_button; }; diff --git a/src/wx/wscript b/src/wx/wscript index e0566a6ed..9c3ecdd71 100644 --- a/src/wx/wscript +++ b/src/wx/wscript @@ -9,8 +9,9 @@ sources = """ audio_mapping_view.cc audio_panel.cc audio_plot.cc - colour_conversion_dialog.cc + colour_conversion_editor.cc config_dialog.cc + content_colour_conversion_dialog.cc content_menu.cc dci_metadata_dialog.cc dir_picker_ctrl.cc @@ -18,11 +19,12 @@ sources = """ film_editor_panel.cc film_viewer.cc filter_dialog.cc - filter_view.cc + filter_editor.cc gain_calculator_dialog.cc job_manager_view.cc job_wrapper.cc new_film_dialog.cc + preset_colour_conversion_dialog.cc properties_dialog.cc repeat_dialog.cc server_dialog.cc diff --git a/test/client_server_test.cc b/test/client_server_test.cc index d695f96ce..7faf47c41 100644 --- a/test/client_server_test.cc +++ b/test/client_server_test.cc @@ -29,7 +29,7 @@ using boost::shared_ptr; using boost::thread; void -do_remote_encode (shared_ptr frame, shared_ptr description, shared_ptr locally_encoded) +do_remote_encode (shared_ptr frame, ServerDescription description, shared_ptr locally_encoded) { shared_ptr remotely_encoded; BOOST_CHECK_NO_THROW (remotely_encoded = frame->encode_remotely (description)); @@ -92,7 +92,7 @@ BOOST_AUTO_TEST_CASE (client_server_test) /* Let the server get itself ready */ dcpomatic_sleep (1); - shared_ptr description (new ServerDescription ("localhost", 2)); + ServerDescription description ("localhost", 2); list threads; for (int i = 0; i < 8; ++i) { diff --git a/test/test.cc b/test/test.cc index 21cf18c76..1c7b7e245 100644 --- a/test/test.cc +++ b/test/test.cc @@ -46,7 +46,7 @@ struct TestConfig dcpomatic_setup(); Config::instance()->set_num_local_encoding_threads (1); - Config::instance()->set_servers (vector > ()); + Config::instance()->set_servers (vector ()); Config::instance()->set_server_port (61920); Config::instance()->set_default_dci_metadata (DCIMetadata ()); Config::instance()->set_default_container (static_cast (0)); -- cgit v1.2.3 From 5f64a83b76dd015cc03d106061bf890d3d80d788 Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Sat, 17 Aug 2013 22:21:15 +0100 Subject: Try to actually use colour conversion; bump libdcp in cscript. --- cscript | 2 +- src/lib/dcp_video_frame.cc | 27 +++++++++++++++++++++++---- src/lib/dcp_video_frame.h | 3 ++- src/lib/encoder.cc | 4 ++-- src/lib/encoder.h | 2 +- src/lib/player.cc | 6 +++--- src/lib/player.h | 7 ++++--- src/lib/server.cc | 4 +++- src/lib/transcoder.cc | 6 +++--- src/wx/content_colour_conversion_dialog.cc | 2 +- src/wx/preset_colour_conversion_dialog.cc | 2 +- test/client_server_test.cc | 1 + 12 files changed, 45 insertions(+), 21 deletions(-) (limited to 'src/lib/server.cc') diff --git a/cscript b/cscript index 4004cbdc3..1f14f2f77 100644 --- a/cscript +++ b/cscript @@ -7,7 +7,7 @@ def dependencies(target): return () else: return (('ffmpeg-cdist', '0d76267f36cbf01acd6a2a96ad2f7497a1843862'), - ('libdcp', 'ee5e932cf0afa1ce24ea5eb0f298be8009cd9689')) + ('libdcp', '7b8313c73082cc08b4dc42dc86d0c90a578993b1')) def build(target): cmd = './waf configure --prefix=%s' % target.work_dir_cscript() diff --git a/src/lib/dcp_video_frame.cc b/src/lib/dcp_video_frame.cc index 1cb20b611..cde9f8a32 100644 --- a/src/lib/dcp_video_frame.cc +++ b/src/lib/dcp_video_frame.cc @@ -77,11 +77,12 @@ using libdcp::Size; * @param l Log to write to. */ DCPVideoFrame::DCPVideoFrame ( - shared_ptr image, int f, Eyes eyes, int dcp_fps, int bw, shared_ptr l + shared_ptr image, int f, Eyes eyes, ColourConversion c, int dcp_fps, int bw, shared_ptr l ) : _image (image) , _frame (f) , _eyes (eyes) + , _conversion (c) , _frames_per_second (dcp_fps) , _j2k_bandwidth (bw) , _log (l) @@ -95,11 +96,27 @@ DCPVideoFrame::DCPVideoFrame ( shared_ptr DCPVideoFrame::encode_locally () { + shared_ptr in_lut; + if (_conversion.input_gamma_linearised) { + in_lut = libdcp::SRGBLinearisedGammaLUT::cache.get (12, _conversion.input_gamma); + } else { + in_lut = libdcp::GammaLUT::cache.get (12, _conversion.input_gamma); + } + + /* 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] = _conversion.matrix (i, j); + } + } + shared_ptr xyz = libdcp::rgb_to_xyz ( _image, - libdcp::SRGBLinearisedGammaLUT::cache.get (12, 2.4), - libdcp::GammaLUT::cache.get (16, 1 / 2.6), - libdcp::colour_matrix::srgb_to_xyz + in_lut, + libdcp::GammaLUT::cache.get (16, 1 / _conversion.output_gamma), + matrix ); /* Set the max image and component sizes based on frame_rate */ @@ -224,6 +241,8 @@ DCPVideoFrame::encode_remotely (ServerDescription serv) socket->connect (*endpoint_iterator); + /* XXX: colour conversion! */ + stringstream s; s << "encode please\n" << "width " << _image->size().width << "\n" diff --git a/src/lib/dcp_video_frame.h b/src/lib/dcp_video_frame.h index ce6444293..9e58b5879 100644 --- a/src/lib/dcp_video_frame.h +++ b/src/lib/dcp_video_frame.h @@ -102,7 +102,7 @@ public: class DCPVideoFrame : public boost::noncopyable { public: - DCPVideoFrame (boost::shared_ptr, int, Eyes, int, int, boost::shared_ptr); + DCPVideoFrame (boost::shared_ptr, int, Eyes, ColourConversion, int, int, boost::shared_ptr); boost::shared_ptr encode_locally (); boost::shared_ptr encode_remotely (ServerDescription); @@ -119,6 +119,7 @@ private: boost::shared_ptr _image; int _frame; ///< frame index within the DCP's intrinsic duration Eyes _eyes; + ColourConversion _conversion; int _frames_per_second; ///< Frames per second that we will use for the DCP int _j2k_bandwidth; ///< J2K bandwidth to use diff --git a/src/lib/encoder.cc b/src/lib/encoder.cc index 29fe64e26..ea175f1f4 100644 --- a/src/lib/encoder.cc +++ b/src/lib/encoder.cc @@ -171,7 +171,7 @@ Encoder::frame_done () } void -Encoder::process_video (shared_ptr image, Eyes eyes, bool same) +Encoder::process_video (shared_ptr image, Eyes eyes, ColourConversion conversion, bool same) { boost::mutex::scoped_lock lock (_mutex); @@ -205,7 +205,7 @@ Encoder::process_video (shared_ptr image, Eyes eyes, bool same) TIMING ("adding to queue of %1", _queue.size ()); _queue.push_back (shared_ptr ( new DCPVideoFrame ( - image, _video_frames_out, eyes, _film->video_frame_rate(), + image, _video_frames_out, eyes, conversion, _film->video_frame_rate(), _film->j2k_bandwidth(), _film->log() ) )); diff --git a/src/lib/encoder.h b/src/lib/encoder.h index c0ea30fcb..44134e568 100644 --- a/src/lib/encoder.h +++ b/src/lib/encoder.h @@ -66,7 +66,7 @@ public: * @param i Video frame image. * @param same true if i is the same as the last time we were called. */ - void process_video (boost::shared_ptr i, Eyes eyes, bool same); + void process_video (boost::shared_ptr i, Eyes eyes, ColourConversion, bool same); /** Call with some audio data */ void process_audio (boost::shared_ptr); diff --git a/src/lib/player.cc b/src/lib/player.cc index af2e6216a..f8ccb0142 100644 --- a/src/lib/player.cc +++ b/src/lib/player.cc @@ -276,11 +276,11 @@ Player::process_video (weak_ptr weak_piece, shared_ptr image _last_video = piece->content; #endif - Video (work_image, eyes, same, time); + Video (work_image, eyes, content->colour_conversion(), same, time); time += TIME_HZ / _film->video_frame_rate(); if (frc.repeat) { - Video (work_image, eyes, true, time); + Video (work_image, eyes, content->colour_conversion(), true, time); time += TIME_HZ / _film->video_frame_rate(); } @@ -549,7 +549,7 @@ Player::emit_black () _last_video.reset (); #endif - Video (_black_frame, EYES_BOTH, _last_emit_was_black, _video_position); + Video (_black_frame, EYES_BOTH, ColourConversion(), _last_emit_was_black, _video_position); _video_position += _film->video_frames_to_time (1); _last_emit_was_black = true; } diff --git a/src/lib/player.h b/src/lib/player.h index 85d750f6f..2261f66ea 100644 --- a/src/lib/player.h +++ b/src/lib/player.h @@ -62,10 +62,11 @@ public: /** Emitted when a video frame is ready. * First parameter is the video image. * Second parameter is the eye(s) that should see this image. - * Third parameter is true if the image is the same as the last one that was emitted. - * Fourth parameter is the time. + * Third parameter is the colour conversion that should be used for this image. + * Fourth parameter is true if the image is the same as the last one that was emitted. + * Fifth parameter is the time. */ - boost::signals2::signal, Eyes, bool, Time)> Video; + boost::signals2::signal, Eyes, ColourConversion, bool, Time)> Video; /** Emitted when some audio data is ready */ boost::signals2::signal, Time)> Audio; diff --git a/src/lib/server.cc b/src/lib/server.cc index de265dca4..e4c281172 100644 --- a/src/lib/server.cc +++ b/src/lib/server.cc @@ -112,8 +112,10 @@ Server::process (shared_ptr socket) image->read_from_socket (socket); + /* XXX: colour conversion... */ + DCPVideoFrame dcp_video_frame ( - image, frame, eyes, frames_per_second, j2k_bandwidth, _log + image, frame, eyes, ColourConversion(), frames_per_second, j2k_bandwidth, _log ); shared_ptr encoded = dcp_video_frame.encode_locally (); diff --git a/src/lib/transcoder.cc b/src/lib/transcoder.cc index 3002ef61c..715a158db 100644 --- a/src/lib/transcoder.cc +++ b/src/lib/transcoder.cc @@ -40,11 +40,11 @@ using boost::weak_ptr; using boost::dynamic_pointer_cast; static void -video_proxy (weak_ptr encoder, shared_ptr image, Eyes eyes, bool same) +video_proxy (weak_ptr encoder, shared_ptr image, Eyes eyes, ColourConversion conversion, bool same) { shared_ptr e = encoder.lock (); if (e) { - e->process_video (image, eyes, same); + e->process_video (image, eyes, conversion, same); } } @@ -67,7 +67,7 @@ Transcoder::Transcoder (shared_ptr f, shared_ptr j) , _player (f->make_player ()) , _encoder (new Encoder (f, j)) { - _player->Video.connect (bind (video_proxy, _encoder, _1, _2, _3)); + _player->Video.connect (bind (video_proxy, _encoder, _1, _2, _3, _4)); _player->Audio.connect (bind (audio_proxy, _encoder, _1)); } diff --git a/src/wx/content_colour_conversion_dialog.cc b/src/wx/content_colour_conversion_dialog.cc index 8fca090ad..d8e768bcd 100644 --- a/src/wx/content_colour_conversion_dialog.cc +++ b/src/wx/content_colour_conversion_dialog.cc @@ -44,7 +44,7 @@ ContentColourConversionDialog::ContentColourConversionDialog (wxWindow* parent) table->Add (_preset_choice); overall_sizer->Add (table, 1, wxEXPAND | wxALL, DCPOMATIC_DIALOG_BORDER); - overall_sizer->Add (new wxStaticLine (this, wxID_ANY)); + overall_sizer->Add (new wxStaticLine (this, wxID_ANY), 0, wxEXPAND); overall_sizer->Add (_editor); wxSizer* buttons = CreateSeparatedButtonSizer (wxOK); diff --git a/src/wx/preset_colour_conversion_dialog.cc b/src/wx/preset_colour_conversion_dialog.cc index 8c4a6dbcf..e7f8cf049 100644 --- a/src/wx/preset_colour_conversion_dialog.cc +++ b/src/wx/preset_colour_conversion_dialog.cc @@ -39,7 +39,7 @@ PresetColourConversionDialog::PresetColourConversionDialog (wxWindow* parent) table->Add (_name); overall_sizer->Add (table, 1, wxEXPAND | wxALL, DCPOMATIC_DIALOG_BORDER); - overall_sizer->Add (new wxStaticLine (this, wxID_ANY)); + overall_sizer->Add (new wxStaticLine (this, wxID_ANY), 0, wxEXPAND); overall_sizer->Add (_editor); wxSizer* buttons = CreateSeparatedButtonSizer (wxOK); diff --git a/test/client_server_test.cc b/test/client_server_test.cc index 7faf47c41..8662f54e8 100644 --- a/test/client_server_test.cc +++ b/test/client_server_test.cc @@ -76,6 +76,7 @@ BOOST_AUTO_TEST_CASE (client_server_test) image, 0, EYES_BOTH, + ColourConversion (), 24, 200000000, log -- cgit v1.2.3 From 944cee945a1f923614783471d472db0896f6877a Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Thu, 29 Aug 2013 20:21:47 +0100 Subject: Untested basics of making client/server work again. --- src/lib/config.cc | 3 +- src/lib/dcp_video_frame.cc | 69 ++++++++++++++++++++++++++++++++++++++-------- src/lib/dcp_video_frame.h | 4 +++ src/lib/film.cc | 3 +- src/lib/server.cc | 28 ++++++++----------- src/lib/types.h | 6 ++++ 6 files changed, 83 insertions(+), 30 deletions(-) (limited to 'src/lib/server.cc') diff --git a/src/lib/config.cc b/src/lib/config.cc index b37d49d64..9f981c619 100644 --- a/src/lib/config.cc +++ b/src/lib/config.cc @@ -77,7 +77,8 @@ Config::read () return; } - cxml::File f (file (false), "Config"); + cxml::Document f ("Config"); + f.read_file (file (false)); optional c; _num_local_encoding_threads = f.number_child ("NumLocalEncodingThreads"); diff --git a/src/lib/dcp_video_frame.cc b/src/lib/dcp_video_frame.cc index cde9f8a32..b5b031292 100644 --- a/src/lib/dcp_video_frame.cc +++ b/src/lib/dcp_video_frame.cc @@ -49,6 +49,7 @@ #include #include #include +#include #include "film.h" #include "dcp_video_frame.h" #include "config.h" @@ -66,6 +67,7 @@ using std::stringstream; using std::ofstream; using std::cout; using boost::shared_ptr; +using boost::lexical_cast; using libdcp::Size; #define DCI_COEFFICENT (48.0 / 52.37) @@ -90,6 +92,26 @@ DCPVideoFrame::DCPVideoFrame ( } +DCPVideoFrame::DCPVideoFrame (shared_ptr image, shared_ptr node, shared_ptr log) + : _image (image) + , _log (log) +{ + _frame = node->number_child ("Frame"); + string const eyes = node->string_child ("Eyes"); + if (eyes == "Both") { + _eyes = EYES_BOTH; + } else if (eyes == "Left") { + _eyes = EYES_LEFT; + } else if (eyes == "Right") { + _eyes = EYES_RIGHT; + } else { + assert (false); + } + _conversion = ColourConversion (node->node_child ("ColourConversion")); + _frames_per_second = node->number_child ("FramesPerSecond"); + _j2k_bandwidth = node->number_child ("J2KBandwidth"); +} + /** J2K-encode this frame on the local host. * @return Encoded data. */ @@ -241,16 +263,16 @@ DCPVideoFrame::encode_remotely (ServerDescription serv) socket->connect (*endpoint_iterator); - /* XXX: colour conversion! */ + xmlpp::Document doc; + xmlpp::Element* root = doc.create_root_node ("EncodingRequest"); - stringstream s; - s << "encode please\n" - << "width " << _image->size().width << "\n" - << "height " << _image->size().height << "\n" - << "eyes " << static_cast (_eyes) << "\n" - << "frame " << _frame << "\n" - << "frames_per_second " << _frames_per_second << "\n" - << "j2k_bandwidth " << _j2k_bandwidth << "\n"; + root->add_child("Version")->add_child_text (lexical_cast (SERVER_LINK_VERSION)); + root->add_child("Width")->add_child_text (lexical_cast (_image->size().width)); + root->add_child("Height")->add_child_text (lexical_cast (_image->size().height)); + add_metadata (root); + + stringstream xml; + doc.write_to_stream (xml); _log->log (String::compose ( N_("Sending to remote; pixel format %1, components %2, lines (%3,%4,%5), line sizes (%6,%7,%8)"), @@ -259,8 +281,8 @@ DCPVideoFrame::encode_remotely (ServerDescription serv) _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); + socket->write (xml.str().length() + 1); + socket->write ((uint8_t *) xml.str().c_str(), xml.str().length() + 1); _image->write_to_socket (socket); @@ -272,6 +294,31 @@ DCPVideoFrame::encode_remotely (ServerDescription serv) return e; } +void +DCPVideoFrame::add_metadata (xmlpp::Element* el) const +{ + el->add_child("Frame")->add_child_text (lexical_cast (_frame)); + + switch (_eyes) { + case EYES_BOTH: + el->add_child("Eyes")->add_child_text ("Both"); + break; + case EYES_LEFT: + el->add_child("Eyes")->add_child_text ("Left"); + break; + case EYES_RIGHT: + el->add_child("Eyes")->add_child_text ("Right"); + break; + default: + assert (false); + } + + _conversion.as_xml (el->add_child("ColourConversion")); + + el->add_child("FramesPerSecond")->add_child_text (lexical_cast (_frames_per_second)); + el->add_child("J2KBandwidth")->add_child_text (lexical_cast (_j2k_bandwidth)); +} + EncodedData::EncodedData (int s) : _data (new uint8_t[s]) , _size (s) diff --git a/src/lib/dcp_video_frame.h b/src/lib/dcp_video_frame.h index 9e58b5879..bf0b7f8c4 100644 --- a/src/lib/dcp_video_frame.h +++ b/src/lib/dcp_video_frame.h @@ -103,6 +103,7 @@ class DCPVideoFrame : public boost::noncopyable { public: DCPVideoFrame (boost::shared_ptr, int, Eyes, ColourConversion, int, int, boost::shared_ptr); + DCPVideoFrame (boost::shared_ptr, boost::shared_ptr, boost::shared_ptr); boost::shared_ptr encode_locally (); boost::shared_ptr encode_remotely (ServerDescription); @@ -116,6 +117,9 @@ public: } private: + + void add_metadata (xmlpp::Element *) const; + boost::shared_ptr _image; int _frame; ///< frame index within the DCP's intrinsic duration Eyes _eyes; diff --git a/src/lib/film.cc b/src/lib/film.cc index e235ee003..940e94fa7 100644 --- a/src/lib/film.cc +++ b/src/lib/film.cc @@ -356,7 +356,8 @@ Film::read_metadata () throw StringError (_("This film was created with an older version of DCP-o-matic, and unfortunately it cannot be loaded into this version. You will need to create a new Film, re-add your content and set it up again. Sorry!")); } - cxml::File f (file ("metadata.xml"), "Metadata"); + cxml::Document f ("Metadata"); + f.read_file (file ("metadata.xml")); _name = f.string_child ("Name"); _use_dci_name = f.bool_child ("UseDCIName"); diff --git a/src/lib/server.cc b/src/lib/server.cc index e4c281172..0212dbbed 100644 --- a/src/lib/server.cc +++ b/src/lib/server.cc @@ -96,41 +96,35 @@ Server::process (shared_ptr socket) socket->read (reinterpret_cast (buffer.get()), length); stringstream s (buffer.get()); - multimap kv = read_key_value (s); - - if (get_required_string (kv, "encode") != "please") { + shared_ptr xml (new cxml::Document ("EncodingRequest")); + xml->read_stream (s); + if (xml->number_child ("Version") != SERVER_LINK_VERSION) { + _log->log ("Mismatched server/client versions"); return -1; } - 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 j2k_bandwidth = get_required_int (kv, "j2k_bandwidth"); - Eyes eyes = static_cast (get_required_int (kv, "eyes")); + libdcp::Size size ( + xml->number_child ("Width"), xml->number_child ("Height") + ); shared_ptr image (new Image (PIX_FMT_RGB24, size, true)); image->read_from_socket (socket); - - /* XXX: colour conversion... */ - - DCPVideoFrame dcp_video_frame ( - image, frame, eyes, ColourConversion(), frames_per_second, j2k_bandwidth, _log - ); + DCPVideoFrame dcp_video_frame (image, xml, _log); shared_ptr encoded = dcp_video_frame.encode_locally (); try { encoded->send (socket); } catch (std::exception& e) { _log->log (String::compose ( - N_("Send failed; frame %1, data size %2, pixel format %3, image size %4x%5, %6 components"), - frame, encoded->size(), image->pixel_format(), image->size().width, image->size().height, image->components() + "Send failed; frame %1, data size %2, pixel format %3, image size %4x%5, %6 components", + dcp_video_frame.frame(), encoded->size(), image->pixel_format(), image->size().width, image->size().height, image->components() ) ); throw; } - return frame; + return dcp_video_frame.frame (); } void diff --git a/src/lib/types.h b/src/lib/types.h index e1487ed4d..01560ba81 100644 --- a/src/lib/types.h +++ b/src/lib/types.h @@ -28,6 +28,12 @@ class Content; class AudioBuffers; +/** The version number of the protocol used to communicate + * with servers. Intended to be bumped when incompatibilities + * are introduced. + */ +#define SERVER_LINK_VERSION 1 + typedef int64_t Time; #define TIME_MAX INT64_MAX #define TIME_HZ ((Time) 96000) -- cgit v1.2.3