Merge master.
authorCarl Hetherington <cth@carlh.net>
Mon, 2 Jun 2014 11:06:20 +0000 (12:06 +0100)
committerCarl Hetherington <cth@carlh.net>
Mon, 2 Jun 2014 11:06:20 +0000 (12:06 +0100)
34 files changed:
1  2 
ChangeLog
src/lib/config.cc
src/lib/config.h
src/lib/content.h
src/lib/cross.cc
src/lib/dcp_video_frame.cc
src/lib/decoder.h
src/lib/encoder.cc
src/lib/ffmpeg_content.cc
src/lib/ffmpeg_decoder.cc
src/lib/ffmpeg_examiner.cc
src/lib/film.cc
src/lib/film.h
src/lib/image_decoder.cc
src/lib/image_proxy.cc
src/lib/job.cc
src/lib/kdm.cc
src/lib/kdm.h
src/lib/player.cc
src/lib/player_video_frame.cc
src/lib/player_video_frame.h
src/lib/server.cc
src/lib/transcode_job.cc
src/lib/types.h
src/lib/util.h
src/lib/writer.cc
src/tools/dcpomatic.cc
src/tools/dcpomatic_cli.cc
src/tools/dcpomatic_kdm.cc
src/wx/about_dialog.cc
src/wx/config_dialog.cc
src/wx/film_editor.cc
test/client_server_test.cc
test/ffmpeg_dcp_test.cc

diff --cc ChangeLog
index 6f31dd5d24fbcd839fa07968a0e32c77d0e27977,bd7ec7c621edf3f6d1e2cbe3cd67b0aa0cbf23b1..e31fc719ebcf398dddbe0f0ee605bc0620b00612
+++ b/ChangeLog
@@@ -1,7 -1,60 +1,64 @@@
 +2014-03-07  Carl Hetherington  <cth@carlh.net>
 +
 +      * Add subtitle view.
 +
+ 2014-05-29  Carl Hetherington  <cth@carlh.net>
+       * Version 1.69.18 released.
+ 2014-05-28  Carl Hetherington  <cth@carlh.net>
+       * Version 1.69.17 released.
+ 2014-05-28  Carl Hetherington  <cth@carlh.net>
+       * Version 1.69.16 released.
+ 2014-05-28  Carl Hetherington  <cth@carlh.net>
+       * Rework KDM generation to be about CPLs rather than DCPs,
+       and allow specification of any CPL to generate KDMs for.
+       Requested-by: Richard Turner
+ 2014-05-27  Carl Hetherington  <cth@carlh.net>
+       * Version 1.69.15 released.
+ 2014-05-26  Carl Hetherington  <cth@carlh.net>
+       * Version 1.69.14 released.
+ 2014-05-26  Carl Hetherington  <cth@carlh.net>
+       * Fix problems with non-zero FFmpeg content start times.
+ 2014-05-24  Carl Hetherington  <cth@carlh.net>
+       * Version 1.69.13 released.
+ 2014-05-24  Carl Hetherington  <cth@carlh.net>
+       * Fix problems with log setup from config.
+ 2014-05-23  Carl Hetherington  <cth@carlh.net>
+       * Version 1.69.12 released.
+ 2014-05-22  Carl Hetherington  <cth@carlh.net>
+       * Version 1.69.11 released.
+ 2014-05-21  Carl Hetherington  <cth@carlh.net>
+       * Version 1.69.10 released.
+ 2014-05-21  Carl Hetherington  <cth@carlh.net>
+       * Tidy up logging a bit and make it configurable from the GUI
+       (moving a few things into an Advanced preferences tab at
+       the same time).
  2014-05-19  Carl Hetherington  <cth@carlh.net>
  
        * Version 1.69.9 released.
Simple merge
Simple merge
index 1d3764c20192bd883f5efffe79249e736325f79a,596a0a905c95217d4daaf8ba116b8a6f518c6555..6bbf33b35cd4d4e10377bdda2ad77be6cf673f7c
@@@ -138,6 -129,8 +138,10 @@@ public
                _change_signals_frequent = f;
        }
  
 -      bool trimmed (Time) const;
++      boost::shared_ptr<const Film> film () const {
++              return _film.lock ();
++      }
        boost::signals2::signal<void (boost::weak_ptr<Content>, int, bool)> Changed;
  
  protected:
Simple merge
Simple merge
index 0ec73ba91f47147af16b057dcef31004a0b75c47,d67592ed812544c644b8766bcb1b1be1c03e84de..18f612e538c5e645470c33cfcca91175a58a0b13
  #include <boost/shared_ptr.hpp>
  #include <boost/weak_ptr.hpp>
  #include <boost/utility.hpp>
 +#include "types.h"
 +#include "dcpomatic_time.h"
  
 -class Film;
 +class Decoded;
- class Film;
  
  /** @class Decoder.
   *  @brief Parent class for decoders of content.
index 2364b67a7ceccb5a1ced874efad51b83228fdcaa,e83ac70f52a379cef6688f00e0c72a284544abf5..5dc9e47c772cb7ec0e7c13a91b332c54bce63307
@@@ -209,15 -214,16 +212,15 @@@ Encoder::process_video (shared_ptr<Play
                frame_done ();
        } else {
                /* Queue this new frame for encoding */
-               TIMING ("adding to queue of %1", _queue.size ());
+               LOG_TIMING ("adding to queue of %1", _queue.size ());
                _queue.push_back (shared_ptr<DCPVideoFrame> (
                                          new DCPVideoFrame (
 -                                                pvf, _video_frames_out, _film->video_frame_rate(),
 -                                                _film->j2k_bandwidth(), _film->resolution(), _film->log()
 +                                                pvf,
 +                                                _video_frames_out,
 +                                                _film->video_frame_rate(),
 +                                                _film->j2k_bandwidth(),
 +                                                _film->resolution(),
 +                                                _film->log()
                                                  )
                                          ));
                
index 2b507ab371adf3187c08d5b1241ff80c7f359edc,41a3724a29cfee6b19523a776fd0edcb773542ea..9889d511cd45016c97b08746bce15856a953e265
@@@ -166,14 -166,14 +168,14 @@@ FFmpegContent::examine (shared_ptr<Job
  
        Content::examine (job);
  
 -      shared_ptr<const Film> film = _film.lock ();
 -      assert (film);
 -
        shared_ptr<FFmpegExaminer> examiner (new FFmpegExaminer (shared_from_this ()));
 +      take_from_video_examiner (examiner);
 +
 +      ContentTime video_length = examiner->video_length ();
  
 -      VideoContent::Frame video_length = 0;
 -      video_length = examiner->video_length ();
 -      LOG_GENERAL ("Video length obtained from header as %1 frames", video_length);
 +      shared_ptr<const Film> film = _film.lock ();
 +      assert (film);
-       film->log()->log (String::compose ("Video length obtained from header as %1 frames", video_length.frames (video_frame_rate ())));
++      LOG_GENERAL ("Video length obtained from header as %1 frames", video_length.frames (video_frame_rate ()));
  
        {
                boost::mutex::scoped_lock lm (_mutex);
index d668deb6f6bbeee617128acbe05489e30874f9a4,5fe34ce14fb3430749f522b93de4aa2971621ff3..0dae2a4edc41be11d70855d94e93b9594dc27c39
@@@ -44,9 -43,13 +44,14 @@@ extern "C" 
  #include "audio_buffers.h"
  #include "ffmpeg_content.h"
  #include "image_proxy.h"
++#include "film.h"
  
  #include "i18n.h"
  
 -#define LOG_GENERAL(...) film->log()->log (String::compose (__VA_ARGS__), Log::TYPE_GENERAL);
 -#define LOG_ERROR(...) film->log()->log (String::compose (__VA_ARGS__), Log::TYPE_ERROR);
 -#define LOG_WARNING(...) film->log()->log (__VA_ARGS__, Log::TYPE_WARNING);
++#define LOG_GENERAL(...) _video_content->film()->log()->log (String::compose (__VA_ARGS__), Log::TYPE_GENERAL);
++#define LOG_ERROR(...) _video_content->film()->log()->log (String::compose (__VA_ARGS__), Log::TYPE_ERROR);
++#define LOG_WARNING(...) _video_content->film()->log()->log (__VA_ARGS__, Log::TYPE_WARNING);
  using std::cout;
  using std::string;
  using std::vector;
@@@ -138,7 -160,9 +143,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));
-                       _log->log (String::compose (N_("error on av_read_frame (%1) (%2)"), buf, r));
 -                      shared_ptr<const Film> film = _film.lock ();
 -                      assert (film);
+                       LOG_ERROR (N_("error on av_read_frame (%1) (%2)"), buf, r);
                }
  
                flush ();
@@@ -429,9 -401,10 +434,9 @@@ FFmpegDecoder::decode_audio_packet (
  
                int frame_finished;
                int const decode_result = avcodec_decode_audio4 (audio_codec_context(), _frame, &frame_finished, &copy_packet);
 +
                if (decode_result < 0) {
-                       _log->log (String::compose ("avcodec_decode_audio4 failed (%1)", decode_result));
 -                      shared_ptr<const Film> film = _film.lock ();
 -                      assert (film);
+                       LOG_ERROR ("avcodec_decode_audio4 failed (%1)", decode_result);
                        return;
                }
  
@@@ -471,9 -459,13 +476,9 @@@ FFmpegDecoder::decode_video_packet (
        }
  
        if (i == _filter_graphs.end ()) {
 -              shared_ptr<const Film> film = _film.lock ();
 -              assert (film);
 -
 -              graph.reset (new FilterGraph (_ffmpeg_content, libdcp::Size (_frame->width, _frame->height), (AVPixelFormat) _frame->format));
 +              graph.reset (new FilterGraph (_ffmpeg_content, dcp::Size (_frame->width, _frame->height), (AVPixelFormat) _frame->format));
                _filter_graphs.push_back (graph);
-               _log->log (String::compose (N_("New graph for %1x%2, pixel format %3"), _frame->width, _frame->height, _frame->format));
 -
+               LOG_GENERAL (N_("New graph for %1x%2, pixel format %3"), _frame->width, _frame->height, _frame->format);
        } else {
                graph = *i;
        }
                shared_ptr<Image> image = i->first;
                
                if (i->second != AV_NOPTS_VALUE) {
 -
 -                      double const pts = i->second * av_q2d (_format_context->streams[_video_stream]->time_base) + _pts_offset;
 -
 -                      if (_just_sought) {
 -                              /* We just did a seek, so disable any attempts to correct for where we
 -                                 are / should be.
 -                              */
 -                              _video_position = rint (pts * _ffmpeg_content->video_frame_rate ());
 -                              _just_sought = false;
 -                      }
 -
 -                      double const next = _video_position / _ffmpeg_content->video_frame_rate();
 -                      double const one_frame = 1 / _ffmpeg_content->video_frame_rate ();
 -                      double delta = pts - next;
 -
 -                      while (delta > one_frame) {
 -                              /* This PTS is more than one frame forward in time of where we think we should be; emit
 -                                 a black frame.
 -                              */
 -
 -                              /* XXX: I think this should be a copy of the last frame... */
 -                              boost::shared_ptr<Image> black (
 -                                      new Image (
 -                                              static_cast<AVPixelFormat> (_frame->format),
 -                                              libdcp::Size (video_codec_context()->width, video_codec_context()->height),
 -                                              true
 -                                              )
 -                                      );
 -                              
 -                              shared_ptr<const Film> film = _film.lock ();
 -                              assert (film);
 -
 -                              black->make_black ();
 -                              video (shared_ptr<ImageProxy> (new RawImageProxy (image, film->log())), false, _video_position);
 -                              delta -= one_frame;
 -                      }
 -
 -                      if (delta > -one_frame) {
 -                              /* This PTS is within a frame of being right; emit this (otherwise it will be dropped) */
 -                              video (shared_ptr<ImageProxy> (new RawImageProxy (image, film->log())), false, _video_position);
 -                      }
 -                              
 +                      double const pts = i->second * av_q2d (_format_context->streams[_video_stream]->time_base) + _pts_offset.seconds ();
-                       video (shared_ptr<ImageProxy> (new RawImageProxy (image)), rint (pts * _ffmpeg_content->video_frame_rate ()));
++                      video (
++                              shared_ptr<ImageProxy> (new RawImageProxy (image, _video_content->film()->log())),
++                              rint (pts * _ffmpeg_content->video_frame_rate ())
++                              );
                } else {
-                       _log->log ("Dropping frame without PTS");
+                       LOG_WARNING ("Dropping frame without PTS");
                }
        }
  
index df12830f819eb182c2c04db9838e71f550e236ff,d73063083f894fa82a39e5dd316796ac97f79589..d9bcedfc528f196ba9a85b064d1f3900f32fdbbc
@@@ -159,25 -118,27 +159,25 @@@ FFmpegExaminer::frame_time (AVStream* s
  float
  FFmpegExaminer::video_frame_rate () const
  {
 -      AVStream* s = _format_context->streams[_video_stream];
 -
 -      if (s->avg_frame_rate.num && s->avg_frame_rate.den) {
 -              return av_q2d (s->avg_frame_rate);
 -      }
 -
 -      return av_q2d (s->r_frame_rate);
 +      /* This use of r_frame_rate is debateable; there's a few different
 +       * frame rates in the format context, but this one seems to be the most
 +       * reliable.
 +       */
 +      return av_q2d (av_stream_get_r_frame_rate (_format_context->streams[_video_stream]));
  }
  
 -libdcp::Size
 +dcp::Size
  FFmpegExaminer::video_size () const
  {
 -      return libdcp::Size (video_codec_context()->width, video_codec_context()->height);
 +      return dcp::Size (video_codec_context()->width, video_codec_context()->height);
  }
  
 -/** @return Length (in video frames) according to our content's header */
 -VideoContent::Frame
 +/** @return Length according to our content's header */
 +ContentTime
  FFmpegExaminer::video_length () const
  {
-       ContentTime const length = ContentTime::from_seconds (double (_format_context->duration) / AV_TIME_BASE);
 -      VideoContent::Frame const length = (double (_format_context->duration - _format_context->start_time) / AV_TIME_BASE) * video_frame_rate();
 -      return max (1, length);
++      ContentTime const length = ContentTime::from_seconds (double (_format_context->duration - _format_context->start_time) / AV_TIME_BASE);
 +      return ContentTime (max (int64_t (1), length.get ()));
  }
  
  string
diff --cc src/lib/film.cc
index 50b1b4fad309e18c7bd848f829fce4e159b8fad6,1b5b2b36601e64eb519b4dfa20f1d13abd298053..25730ae1cbe8bff7e07da16c6eced81e099c7c79
@@@ -77,10 -77,13 +77,13 @@@ using boost::to_upper_copy
  using boost::ends_with;
  using boost::starts_with;
  using boost::optional;
 -using libdcp::Size;
 -using libdcp::Signer;
 -using libdcp::raw_convert;
 +using dcp::Size;
 +using dcp::Signer;
 +using dcp::raw_convert;
  
+ #define LOG_GENERAL(...) log()->log (String::compose (__VA_ARGS__), Log::TYPE_GENERAL);
+ #define LOG_GENERAL_NC(...) log()->log (__VA_ARGS__, Log::TYPE_GENERAL);
  /* 5 -> 6
   * AudioMapping XML changed.
   * 6 -> 7
@@@ -780,9 -780,13 +783,16 @@@ Film::cpls () cons
                        ) {
  
                        try {
 -                              libdcp::DCP dcp (*i);
 +                              dcp::DCP dcp (*i);
                                dcp.read ();
-                               out.push_back (i->path().leaf ());
+                               out.push_back (
+                                       CPLSummary (
 -                                              i->path().leaf().string(), dcp.cpls().front()->id(), dcp.cpls().front()->name(), dcp.cpls().front()->filename()
++                                              i->path().leaf().string(),
++                                              dcp.cpls().front()->id(),
++                                              dcp.cpls().front()->annotation_text(),
++                                              dcp.cpls().front()->file()
+                                               )
+                                       );
                        } catch (...) {
  
                        }
@@@ -958,32 -980,27 +968,21 @@@ Film::frame_size () cons
        return fit_ratio_within (container()->ratio(), full_frame ());
  }
  
 -/** @param from KDM from time in local time.
 - *  @param to KDM to time in local time.
 - */
 -libdcp::KDM
 +dcp::EncryptedKDM
  Film::make_kdm (
 -      shared_ptr<libdcp::Certificate> target,
 +      shared_ptr<dcp::Certificate> target,
-       boost::filesystem::path dcp_dir,
+       boost::filesystem::path cpl_file,
 -      boost::posix_time::ptime from,
 -      boost::posix_time::ptime until
 +      dcp::LocalTime from,
 +      dcp::LocalTime until
        ) const
  {
--      shared_ptr<const Signer> signer = make_signer ();
--
-       dcp::DCP dcp (dir (dcp_dir.string ()));
-       
-       try {
-               dcp.read ();
-       } catch (...) {
-               throw KDMError (_("Could not read DCP to make KDM for"));
-       }
-       
-       dcp.cpls().front()->set_mxf_keys (key ());
 -      time_t now = time (0);
 -      struct tm* tm = localtime (&now);
 -      string const issue_date = libdcp::tm_to_string (tm);
--      
 -      return libdcp::KDM (cpl_file, signer, target, key (), from, until, "DCP-o-matic", issue_date);
++      shared_ptr<const dcp::CPL> cpl (new dcp::CPL (cpl_file));
 +      return dcp::DecryptedKDM (
-               dcp.cpls().front(), from, until, "DCP-o-matic", dcp.cpls().front()->content_title_text(), dcp::LocalTime().as_string()
-               ).encrypt (signer, target);
++              cpl, from, until, "DCP-o-matic", cpl->content_title_text(), dcp::LocalTime().as_string()
++              ).encrypt (make_signer(), target);
  }
  
 -list<libdcp::KDM>
 +list<dcp::EncryptedKDM>
  Film::make_kdms (
        list<shared_ptr<Screen> > screens,
        boost::filesystem::path dcp,
diff --cc src/lib/film.h
index ee8756b3dfdcf860d837c0dd90a11188427bd350,06c770efadc2860ced9e4dcce4b98d2e2aa643db..d9d7e82fd2140a4cbf9fae20c69ea9e6badd4db6
@@@ -96,10 -95,10 +96,10 @@@ public
                return _dirty;
        }
  
 -      libdcp::Size full_frame () const;
 -      libdcp::Size frame_size () const;
 +      dcp::Size full_frame () const;
 +      dcp::Size frame_size () const;
  
-       std::list<boost::filesystem::path> dcps () const;
+       std::vector<CPLSummary> cpls () const;
  
        boost::shared_ptr<Player> make_player () const;
        boost::shared_ptr<Playlist> playlist () const;
        /* Proxies for some Playlist methods */
  
        ContentList content () const;
 -      Time length () const;
 +      DCPTime length () const;
        bool has_subtitles () const;
 -      OutputVideoFrame best_video_frame_rate () const;
 +      int best_video_frame_rate () const;
 +      FrameRateChange active_frame_rate_change (DCPTime) const;
  
 -      libdcp::KDM
 +      dcp::EncryptedKDM
        make_kdm (
 -              boost::shared_ptr<libdcp::Certificate> target,
 +              boost::shared_ptr<dcp::Certificate> target,
-               boost::filesystem::path dcp,
+               boost::filesystem::path cpl_file,
 -              boost::posix_time::ptime from,
 -              boost::posix_time::ptime until
 +              dcp::LocalTime from,
 +              dcp::LocalTime until
                ) const;
        
 -      std::list<libdcp::KDM> make_kdms (
 +      std::list<dcp::EncryptedKDM> make_kdms (
                std::list<boost::shared_ptr<Screen> >,
-               boost::filesystem::path dcp,
+               boost::filesystem::path cpl_file,
 -              boost::posix_time::ptime from,
 -              boost::posix_time::ptime until
 +              dcp::LocalTime from,
 +              dcp::LocalTime until
                ) const;
  
 -      libdcp::Key key () const {
 +      dcp::Key key () const {
                return _key;
        }
  
index 9f83d1d896d1444579bcd157b214b389468b9f30,7a9acd9e4960e611bda76e912e4837738e94dc59..d3cdbd6f1ee753b994919cd677828662c1b96a8e
@@@ -40,21 -41,23 +40,21 @@@ ImageDecoder::ImageDecoder (shared_ptr<
  
  }
  
 -void
 +bool
  ImageDecoder::pass ()
  {
 -      if (_video_position >= _image_content->video_length ()) {
 -              return;
 +      if (_video_position >= _image_content->video_length().frames (_image_content->video_frame_rate ())) {
 +              return true;
        }
  
 -      if (_image && _image_content->still ()) {
 -              video (_image, true, _video_position);
 -              return;
 +      if (!_image_content->still() || !_image) {
 +              /* Either we need an image or we are using moving images, so load one */
-               _image.reset (new MagickImageProxy (_image_content->path (_image_content->still() ? 0 : _video_position)));
++              _image.reset (new MagickImageProxy (_image_content->path (_image_content->still() ? 0 : _video_position), _image_content->film()->log ()));
        }
 -
 -      shared_ptr<const Film> film = _film.lock ();
 -      assert (film);
 -
 -      _image.reset (new MagickImageProxy (_image_content->path (_image_content->still() ? 0 : _video_position), film->log ()));
 -      video (_image, false, _video_position);
 +              
 +      video (_image, _video_position);
 +      ++_video_position;
 +      return false;
  }
  
  void
index c74e846c99680b1e0e3f4ab0319ad17c109f1c9a,230bfacadc51cfba2dcf6eeb76b281da95e895cd..16bd92f6ece1ea0f933cc0b09ec8a168533c0ece
@@@ -38,9 -41,17 +41,17 @@@ ImageProxy::ImageProxy (shared_ptr<Log
  
  }
  
- RawImageProxy::RawImageProxy (shared_ptr<cxml::Node> xml, shared_ptr<Socket> socket)
+ RawImageProxy::RawImageProxy (shared_ptr<Image> image, shared_ptr<Log> log)
+       : ImageProxy (log)
+       , _image (image)
+ {
+ }
+ RawImageProxy::RawImageProxy (shared_ptr<cxml::Node> xml, shared_ptr<Socket> socket, shared_ptr<Log> log)
+       : ImageProxy (log)
  {
 -      libdcp::Size size (
 +      dcp::Size size (
                xml->number_child<int> ("Width"), xml->number_child<int> ("Height")
                );
  
@@@ -112,8 -127,10 +127,9 @@@ MagickImageProxy::image () cons
                throw DecodeError (_("Could not decode image file"));
        }
  
 +      dcp::Size size (magick_image->columns(), magick_image->rows());
+       LOG_TIMING ("[%1] MagickImageProxy decode finished", boost::this_thread::get_id ());
  
 -      libdcp::Size size (magick_image->columns(), magick_image->rows());
 -
        _image.reset (new Image (PIX_FMT_RGB24, size, true));
  
        using namespace MagickCore;
diff --cc src/lib/job.cc
index c6a6b90a808fcdd234c053ce1c21a31d3128d3eb,96aedac65bf4fb8718d8749712db3ae28d9ae627..594c0da34f1b5cdc7a55177e61bee698b5ac21d5
@@@ -281,7 -279,6 +281,7 @@@ Job::error_summary () cons
  void
  Job::set_error (string s, string d)
  {
-       _film->log()->log (String::compose ("Error in job: %1 (%2)", s, d));
++      _film->log()->log (String::compose ("Error in job: %1 (%2)", s, d), Log::TYPE_ERROR);
        boost::mutex::scoped_lock lm (_state_mutex);
        _error_summary = s;
        _error_details = d;
diff --cc src/lib/kdm.cc
index 902f0d33322a48617e71e193801780704a46ca39,d5d5ec0a0b16d5e503070d09c158b4ff61733ee6..c08750961e2c7c77245191e8e99f2b97daf5d875
@@@ -102,12 -102,12 +102,12 @@@ static list<ScreenKDM
  make_screen_kdms (
        shared_ptr<const Film> film,
        list<shared_ptr<Screen> > screens,
-       boost::filesystem::path dcp,
+       boost::filesystem::path cpl,
 -      boost::posix_time::ptime from,
 -      boost::posix_time::ptime to
 +      dcp::LocalTime from,
 +      dcp::LocalTime to
        )
  {
-       list<dcp::EncryptedKDM> kdms = film->make_kdms (screens, dcp, from, to);
 -      list<libdcp::KDM> kdms = film->make_kdms (screens, cpl, from, to);
++      list<dcp::EncryptedKDM> kdms = film->make_kdms (screens, cpl, from, to);
           
        list<ScreenKDM> screen_kdms;
        
@@@ -126,12 -126,12 +126,12 @@@ static list<CinemaKDMs
  make_cinema_kdms (
        shared_ptr<const Film> film,
        list<shared_ptr<Screen> > screens,
-       boost::filesystem::path dcp,
+       boost::filesystem::path cpl,
 -      boost::posix_time::ptime from,
 -      boost::posix_time::ptime to
 +      dcp::LocalTime from,
 +      dcp::LocalTime to
        )
  {
-       list<ScreenKDM> screen_kdms = make_screen_kdms (film, screens, dcp, from, to);
+       list<ScreenKDM> screen_kdms = make_screen_kdms (film, screens, cpl, from, to);
        list<CinemaKDMs> cinema_kdms;
  
        while (!screen_kdms.empty ()) {
@@@ -171,9 -171,9 +171,9 @@@ voi
  write_kdm_files (
        shared_ptr<const Film> film,
        list<shared_ptr<Screen> > screens,
-       boost::filesystem::path dcp,
+       boost::filesystem::path cpl,
 -      boost::posix_time::ptime from,
 -      boost::posix_time::ptime to,
 +      dcp::LocalTime from,
 +      dcp::LocalTime to,
        boost::filesystem::path directory
        )
  {
@@@ -191,9 -191,9 +191,9 @@@ voi
  write_kdm_zip_files (
        shared_ptr<const Film> film,
        list<shared_ptr<Screen> > screens,
-       boost::filesystem::path dcp,
+       boost::filesystem::path cpl,
 -      boost::posix_time::ptime from,
 -      boost::posix_time::ptime to,
 +      dcp::LocalTime from,
 +      dcp::LocalTime to,
        boost::filesystem::path directory
        )
  {
@@@ -210,12 -210,12 +210,12 @@@ voi
  email_kdms (
        shared_ptr<const Film> film,
        list<shared_ptr<Screen> > screens,
-       boost::filesystem::path dcp,
+       boost::filesystem::path cpl,
 -      boost::posix_time::ptime from,
 -      boost::posix_time::ptime to
 +      dcp::LocalTime from,
 +      dcp::LocalTime to
        )
  {
-       list<CinemaKDMs> cinema_kdms = make_cinema_kdms (film, screens, dcp, from, to);
+       list<CinemaKDMs> cinema_kdms = make_cinema_kdms (film, screens, cpl, from, to);
  
        for (list<CinemaKDMs>::const_iterator i = cinema_kdms.begin(); i != cinema_kdms.end(); ++i) {
                
diff --cc src/lib/kdm.h
index 5df161b2a03404beafc39d88fa2d7dddb0b83e8e,8aacd7b720fe8bfce57c7f75b493d8fb28f17a39..023107a826875f169c4e1c780ee9666ba366eefc
@@@ -26,26 -26,26 +26,26 @@@ class Film
  extern void write_kdm_files (
        boost::shared_ptr<const Film> film,
        std::list<boost::shared_ptr<Screen> > screens,
-       boost::filesystem::path dcp,
+       boost::filesystem::path cpl,
 -      boost::posix_time::ptime from,
 -      boost::posix_time::ptime to,
 +      dcp::LocalTime from,
 +      dcp::LocalTime to,
        boost::filesystem::path directory
        );
  
  extern void write_kdm_zip_files (
        boost::shared_ptr<const Film> film,
        std::list<boost::shared_ptr<Screen> > screens,
-       boost::filesystem::path dcp,
+       boost::filesystem::path cpl,
 -      boost::posix_time::ptime from,
 -      boost::posix_time::ptime to,
 +      dcp::LocalTime from,
 +      dcp::LocalTime to,
        boost::filesystem::path directory
        );
  
  extern void email_kdms (
        boost::shared_ptr<const Film> film,
        std::list<boost::shared_ptr<Screen> > screens,
-       boost::filesystem::path dcp,
+       boost::filesystem::path cpl,
 -      boost::posix_time::ptime from,
 -      boost::posix_time::ptime to
 +      dcp::LocalTime from,
 +      dcp::LocalTime to
        );
  
index b60dd846786056a2918b3a1338a8382183e81cea,b112760ef412a024fa581c9779ca5be4b1c65138..77def1e60d7eec92d83bbe66168fcb562107b827
  #include "image.h"
  #include "image_proxy.h"
  #include "ratio.h"
 -#include "resampler.h"
  #include "log.h"
  #include "scaler.h"
 +#include "render_subtitles.h"
 +#include "config.h"
 +#include "content_video.h"
  #include "player_video_frame.h"
  
+ #define LOG_GENERAL(...) _film->log()->log (String::compose (__VA_ARGS__), Log::TYPE_GENERAL);
  using std::list;
  using std::cout;
  using std::min;
@@@ -283,89 -342,30 +285,89 @@@ Player::process_content_text_subtitles 
  }
  
  void
 -Player::flush ()
 +Player::set_approximate_size ()
  {
 -      TimedAudioBuffers<Time> tb = _audio_merger.flush ();
 -      if (_audio && tb.audio) {
 -              Audio (tb.audio, tb.time);
 -              _audio_position += _film->audio_frames_to_time (tb.audio->frames ());
 -      }
 +      _approximate_size = true;
 +}
  
 -      while (_video && _video_position < _audio_position) {
 -              emit_black ();
 -      }
 +shared_ptr<PlayerVideoFrame>
 +Player::black_player_video_frame () const
 +{
 +      return shared_ptr<PlayerVideoFrame> (
 +              new PlayerVideoFrame (
-                       shared_ptr<const ImageProxy> (new RawImageProxy (_black_image)),
++                      shared_ptr<const ImageProxy> (new RawImageProxy (_black_image, _film->log ())),
 +                      Crop (),
 +                      _video_container_size,
 +                      _video_container_size,
 +                      Scaler::from_id ("bicubic"),
 +                      EYES_BOTH,
 +                      PART_WHOLE,
 +                      Config::instance()->colour_conversions().front().conversion
 +              )
 +      );
 +}
  
 -      while (_audio && _audio_position < _video_position) {
 -              emit_silence (_film->time_to_audio_frames (_video_position - _audio_position));
 +shared_ptr<PlayerVideoFrame>
 +Player::content_to_player_video_frame (
 +      shared_ptr<VideoContent> content,
 +      ContentVideo content_video,
 +      list<shared_ptr<Piece> > subs,
 +      DCPTime time,
 +      dcp::Size image_size) const
 +{
 +      shared_ptr<PlayerVideoFrame> pvf (
 +              new PlayerVideoFrame (
 +                      content_video.image,
 +                      content->crop (),
 +                      image_size,
 +                      _video_container_size,
 +                      _film->scaler(),
 +                      content_video.eyes,
 +                      content_video.part,
 +                      content->colour_conversion ()
 +                      )
 +              );
 +      
 +      
 +      /* Add subtitles */
 +      
 +      list<PositionImage> sub_images;
 +      
 +      for (list<shared_ptr<Piece> >::const_iterator i = subs.begin(); i != subs.end(); ++i) {
 +              shared_ptr<SubtitleDecoder> subtitle_decoder = dynamic_pointer_cast<SubtitleDecoder> ((*i)->decoder);
 +              shared_ptr<SubtitleContent> subtitle_content = dynamic_pointer_cast<SubtitleContent> ((*i)->content);
 +              ContentTime const from = dcp_to_content_subtitle (*i, time);
 +              ContentTime const to = from + ContentTime::from_frames (1, content->video_frame_rate ());
 +              
 +              list<shared_ptr<ContentImageSubtitle> > image_subtitles = subtitle_decoder->get_image_subtitles (ContentTimePeriod (from, to));
 +              if (!image_subtitles.empty ()) {
 +                      list<PositionImage> im = process_content_image_subtitles (
 +                              subtitle_content,
 +                              image_subtitles
 +                              );
 +                      
 +                      copy (im.begin(), im.end(), back_inserter (sub_images));
 +              }
 +              
 +              if (_burn_subtitles) {
 +                      list<shared_ptr<ContentTextSubtitle> > text_subtitles = subtitle_decoder->get_text_subtitles (ContentTimePeriod (from, to));
 +                      if (!text_subtitles.empty ()) {
 +                              list<PositionImage> im = process_content_text_subtitles (text_subtitles);
 +                              copy (im.begin(), im.end(), back_inserter (sub_images));
 +                      }
 +              }
        }
        
 +      if (!sub_images.empty ()) {
 +              pvf->set_subtitle (merge (sub_images));
 +      }
 +
 +      return pvf;
  }
  
 -/** Seek so that the next pass() will yield (approximately) the requested frame.
 - *  Pass accurate = true to try harder to get close to the request.
 - *  @return true on error
 - */
 -void
 -Player::seek (Time t, bool accurate)
 +/** @return All PlayerVideoFrames at the given time (there may be two frames for 3D) */
 +list<shared_ptr<PlayerVideoFrame> >
 +Player::get_video (DCPTime time, bool accurate)
  {
        if (!_have_valid_pieces) {
                setup_pieces ();
@@@ -447,103 -418,220 +449,101 @@@ Player::get_audio (DCPTime time, DCPTim
                        continue;
                }
  
 -              shared_ptr<Piece> piece (new Piece (*i));
 -
 -              /* XXX: into content? */
 -
 -              shared_ptr<const FFmpegContent> fc = dynamic_pointer_cast<const FFmpegContent> (*i);
 -              if (fc) {
 -                      shared_ptr<FFmpegDecoder> fd (new FFmpegDecoder (_film, fc, _video, _audio));
 -                      
 -                      fd->Video.connect (bind (&Player::process_video, this, weak_ptr<Piece> (piece), _1, _2, _3, _4, _5, 0));
 -                      fd->Audio.connect (bind (&Player::process_audio, this, weak_ptr<Piece> (piece), _1, _2));
 -                      fd->Subtitle.connect (bind (&Player::process_subtitle, this, weak_ptr<Piece> (piece), _1, _2, _3, _4));
 -
 -                      fd->seek (fc->time_to_content_video_frames (fc->trim_start ()), true);
 -                      piece->decoder = fd;
 +              /* The time that we should request from the content */
 +              DCPTime request = time - DCPTime::from_seconds (content->audio_delay() / 1000.0);
 +              DCPTime offset;
 +              if (request < DCPTime ()) {
 +                      /* We went off the start of the content, so we will need to offset
 +                         the stuff we get back.
 +                      */
 +                      offset = -request;
 +                      request = DCPTime ();
                }
 -              
 -              shared_ptr<const ImageContent> ic = dynamic_pointer_cast<const ImageContent> (*i);
 -              if (ic) {
 -                      bool reusing = false;
 -                      
 -                      /* See if we can re-use an old ImageDecoder */
 -                      for (list<shared_ptr<Piece> >::const_iterator j = old_pieces.begin(); j != old_pieces.end(); ++j) {
 -                              shared_ptr<ImageDecoder> imd = dynamic_pointer_cast<ImageDecoder> ((*j)->decoder);
 -                              if (imd && imd->content() == ic) {
 -                                      piece = *j;
 -                                      reusing = true;
 -                              }
 -                      }
  
 -                      if (!reusing) {
 -                              shared_ptr<ImageDecoder> id (new ImageDecoder (_film, ic));
 -                              id->Video.connect (bind (&Player::process_video, this, weak_ptr<Piece> (piece), _1, _2, _3, _4, _5, 0));
 -                              piece->decoder = id;
 -                      }
 -              }
 +              AudioFrame const content_frame = dcp_to_content_audio (*i, request);
  
 -              shared_ptr<const SndfileContent> sc = dynamic_pointer_cast<const SndfileContent> (*i);
 -              if (sc) {
 -                      shared_ptr<AudioDecoder> sd (new SndfileDecoder (_film, sc));
 -                      sd->Audio.connect (bind (&Player::process_audio, this, weak_ptr<Piece> (piece), _1, _2));
 +              /* Audio from this piece's decoder (which might be more or less than what we asked for) */
 +              shared_ptr<ContentAudio> all = decoder->get_audio (content_frame, length_frames, accurate);
  
 -                      piece->decoder = sd;
 +              /* Gain */
 +              if (content->audio_gain() != 0) {
 +                      shared_ptr<AudioBuffers> gain (new AudioBuffers (all->audio));
 +                      gain->apply_gain (content->audio_gain ());
 +                      all->audio = gain;
                }
  
 -              _pieces.push_back (piece);
 -      }
 -
 -      _have_valid_pieces = true;
 -}
 -
 -void
 -Player::content_changed (weak_ptr<Content> w, int property, bool frequent)
 -{
 -      shared_ptr<Content> c = w.lock ();
 -      if (!c) {
 -              return;
 -      }
 -
 -      if (
 -              property == ContentProperty::POSITION || property == ContentProperty::LENGTH ||
 -              property == ContentProperty::TRIM_START || property == ContentProperty::TRIM_END ||
 -              property == VideoContentProperty::VIDEO_FRAME_TYPE 
 -              ) {
 -              
 -              _have_valid_pieces = false;
 -              Changed (frequent);
 -
 -      } else if (
 -              property == SubtitleContentProperty::SUBTITLE_X_OFFSET ||
 -              property == SubtitleContentProperty::SUBTITLE_Y_OFFSET ||
 -              property == SubtitleContentProperty::SUBTITLE_SCALE
 -              ) {
 -
 -              for (list<Subtitle>::iterator i = _subtitles.begin(); i != _subtitles.end(); ++i) {
 -                      i->update (_film, _video_container_size);
 +              /* Remap channels */
 +              shared_ptr<AudioBuffers> dcp_mapped (new AudioBuffers (_film->audio_channels(), all->audio->frames()));
 +              dcp_mapped->make_silent ();
 +              AudioMapping map = content->audio_mapping ();
 +              for (int i = 0; i < map.content_channels(); ++i) {
 +                      for (int j = 0; j < _film->audio_channels(); ++j) {
 +                              if (map.get (i, static_cast<dcp::Channel> (j)) > 0) {
 +                                      dcp_mapped->accumulate_channel (
 +                                              all->audio.get(),
 +                                              i,
 +                                              j,
 +                                              map.get (i, static_cast<dcp::Channel> (j))
 +                                              );
 +                              }
 +                      }
                }
                
 -              Changed (frequent);
 +              all->audio = dcp_mapped;
  
 -      } else if (
 -              property == VideoContentProperty::VIDEO_CROP || property == VideoContentProperty::VIDEO_SCALE ||
 -              property == VideoContentProperty::VIDEO_FRAME_RATE
 -              ) {
 -              
 -              Changed (frequent);
 -
 -      } else if (property == ContentProperty::PATH) {
 -
 -              _have_valid_pieces = false;
 -              Changed (frequent);
 +              audio->accumulate_frames (
 +                      all->audio.get(),
 +                      content_frame - all->frame,
 +                      offset.frames (_film->audio_frame_rate()),
 +                      min (AudioFrame (all->audio->frames()), length_frames) - offset.frames (_film->audio_frame_rate ())
 +                      );
        }
-       return audio;
  }
  
 -void
 -Player::playlist_changed ()
 -{
 -      _have_valid_pieces = false;
 -      Changed (false);
 -}
 -
 -void
 -Player::set_video_container_size (libdcp::Size s)
 -{
 -      _video_container_size = s;
 -
 -      shared_ptr<Image> im (new Image (PIX_FMT_RGB24, _video_container_size, true));
 -      im->make_black ();
 -      
 -      _black_frame.reset (
 -              new PlayerVideoFrame (
 -                      shared_ptr<ImageProxy> (new RawImageProxy (im, _film->log ())),
 -                      Crop(),
 -                      _video_container_size,
 -                      _video_container_size,
 -                      Scaler::from_id ("bicubic"),
 -                      EYES_BOTH,
 -                      PART_WHOLE,
 -                      ColourConversion ()
 -                      )
 -              );
 -}
 -
 -shared_ptr<Resampler>
 -Player::resampler (shared_ptr<AudioContent> c, bool create)
 +VideoFrame
 +Player::dcp_to_content_video (shared_ptr<const Piece> piece, DCPTime t) const
  {
 -      map<shared_ptr<AudioContent>, shared_ptr<Resampler> >::iterator i = _resamplers.find (c);
 -      if (i != _resamplers.end ()) {
 -              return i->second;
 -      }
 +      /* s is the offset of t from the start position of this content */
 +      DCPTime s = t - piece->content->position ();
 +      s = DCPTime (max (int64_t (0), s.get ()));
 +      s = DCPTime (min (piece->content->length_after_trim().get(), s.get()));
  
 -      if (!create) {
 -              return shared_ptr<Resampler> ();
 -      }
 -
 -      LOG_GENERAL (
 -              "Creating new resampler for %1 to %2 with %3 channels", c->content_audio_frame_rate(), c->output_audio_frame_rate(), c->audio_channels()
 -              );
 -      
 -      shared_ptr<Resampler> r (new Resampler (c->content_audio_frame_rate(), c->output_audio_frame_rate(), c->audio_channels()));
 -      _resamplers[c] = r;
 -      return r;
 +      /* Convert this to the content frame */
 +      return DCPTime (s + piece->content->trim_start()).frames (_film->video_frame_rate()) * piece->frc.factor ();
  }
  
 -void
 -Player::emit_black ()
 +AudioFrame
 +Player::dcp_to_content_audio (shared_ptr<const Piece> piece, DCPTime t) const
  {
 -#ifdef DCPOMATIC_DEBUG
 -      _last_video.reset ();
 -#endif
 +      /* s is the offset of t from the start position of this content */
 +      DCPTime s = t - piece->content->position ();
 +      s = DCPTime (max (int64_t (0), s.get ()));
 +      s = DCPTime (min (piece->content->length_after_trim().get(), s.get()));
  
 -      Video (_black_frame, _last_emit_was_black, _video_position);
 -      _video_position += _film->video_frames_to_time (1);
 -      _last_emit_was_black = true;
 +      /* Convert this to the content frame */
 +      return DCPTime (s + piece->content->trim_start()).frames (_film->audio_frame_rate());
  }
  
 -void
 -Player::emit_silence (OutputAudioFrame most)
 +ContentTime
 +Player::dcp_to_content_subtitle (shared_ptr<const Piece> piece, DCPTime t) const
  {
 -      if (most == 0) {
 -              return;
 -      }
 -      
 -      OutputAudioFrame N = min (most, _film->audio_frame_rate() / 2);
 -      shared_ptr<AudioBuffers> silence (new AudioBuffers (_film->audio_channels(), N));
 -      silence->make_silent ();
 -      Audio (silence, _audio_position);
 -      _audio_position += _film->audio_frames_to_time (N);
 -}
 -
 -void
 -Player::film_changed (Film::Property p)
 -{
 -      /* Here we should notice Film properties that affect our output, and
 -         alert listeners that our output now would be different to how it was
 -         last time we were run.
 -      */
 +      /* s is the offset of t from the start position of this content */
 +      DCPTime s = t - piece->content->position ();
 +      s = DCPTime (max (int64_t (0), s.get ()));
 +      s = DCPTime (min (piece->content->length_after_trim().get(), s.get()));
  
 -      if (p == Film::SCALER || p == Film::WITH_SUBTITLES || p == Film::CONTAINER || p == Film::VIDEO_FRAME_RATE) {
 -              Changed (false);
 -      }
 +      return ContentTime (s + piece->content->trim_start(), piece->frc);
  }
  
  void
 -Player::process_subtitle (weak_ptr<Piece> weak_piece, shared_ptr<Image> image, dcpomatic::Rect<double> rect, Time from, Time to)
 +PlayerStatistics::dump (shared_ptr<Log> log) const
  {
-       log->log (String::compose ("Video: %1 good %2 skipped %3 black %4 repeat", video.good, video.skip, video.black, video.repeat));
-       log->log (String::compose ("Audio: %1 good %2 skipped %3 silence", audio.good, audio.skip, audio.silence.seconds()));
 -      if (!image) {
 -              /* A null image means that we should stop any current subtitles at `from' */
 -              for (list<Subtitle>::iterator i = _subtitles.begin(); i != _subtitles.end(); ++i) {
 -                      i->set_stop (from);
 -              }
 -      } else {
 -              _subtitles.push_back (Subtitle (_film, _video_container_size, weak_piece, image, rect, from, to));
 -      }
++      log->log (String::compose ("Video: %1 good %2 skipped %3 black %4 repeat", video.good, video.skip, video.black, video.repeat), Log::TYPE_GENERAL);
++      log->log (String::compose ("Audio: %1 good %2 skipped %3 silence", audio.good, audio.skip, audio.silence.seconds()), Log::TYPE_GENERAL);
  }
  
 -/** Re-emit the last frame that was emitted, using current settings for crop, ratio, scaler and subtitles.
 - *  @return false if this could not be done.
 - */
 -bool
 -Player::repeat_last_video ()
 +PlayerStatistics const &
 +Player::statistics () const
  {
 -      if (!_last_incoming_video.image || !_have_valid_pieces) {
 -              return false;
 -      }
 -
 -      process_video (
 -              _last_incoming_video.weak_piece,
 -              _last_incoming_video.image,
 -              _last_incoming_video.eyes,
 -              _last_incoming_video.part,
 -              _last_incoming_video.same,
 -              _last_incoming_video.frame,
 -              _last_incoming_video.extra
 -              );
 -
 -      return true;
 +      return _statistics;
  }
Simple merge
index 225b0a4bafe43c8dee4be008b8e5bdb5b519fb1b,b085cb609e659f59b55f6a709c88b046c2a6a078..4c6a9c63008cd6b30f2898b27e8b9e8974dddd8a
@@@ -35,10 -35,10 +36,10 @@@ class Log
  class PlayerVideoFrame
  {
  public:
 -      PlayerVideoFrame (boost::shared_ptr<const ImageProxy>, Crop, libdcp::Size, libdcp::Size, Scaler const *, Eyes, Part, ColourConversion);
 +      PlayerVideoFrame (boost::shared_ptr<const ImageProxy>, Crop, dcp::Size, dcp::Size, Scaler const *, Eyes, Part, ColourConversion);
-       PlayerVideoFrame (boost::shared_ptr<cxml::Node>, boost::shared_ptr<Socket>);
+       PlayerVideoFrame (boost::shared_ptr<cxml::Node>, boost::shared_ptr<Socket>, boost::shared_ptr<Log>);
  
 -      void set_subtitle (boost::shared_ptr<const Image>, Position<int>);
 +      void set_subtitle (PositionImage);
        
        boost::shared_ptr<Image> image () const;
  
Simple merge
Simple merge
diff --cc src/lib/types.h
Simple merge
diff --cc src/lib/util.h
Simple merge
index 306f6d7f4968c387965014baf084e43668bee5f6,b175843ed62bb0c975543b980c1bd4dc66f83fc9..9410dd565b4a9ba963cda63af72aea763c489511
@@@ -275,8 -276,8 +279,8 @@@ tr
                                break;
                        }
                        case QueueItem::FAKE:
-                               _film->log()->log (String::compose (N_("Writer FAKE-writes %1 to MXF"), qi.frame));
+                               LOG_GENERAL (N_("Writer FAKE-writes %1 to MXF"), qi.frame);
 -                              _picture_asset_writer->fake_write (qi.size);
 +                              _picture_mxf_writer->fake_write (qi.size);
                                _last_written[qi.eyes].reset ();
                                ++_fake_written;
                                break;
@@@ -390,10 -406,13 +393,10 @@@ Writer::finish (
        if (ec) {
                /* hard link failed; copy instead */
                boost::filesystem::copy_file (video_from, video_to);
-               _film->log()->log ("Hard-link failed; fell back to copying");
+               LOG_WARNING_NC ("Hard-link failed; fell back to copying");
        }
  
 -      /* And update the asset */
 -
 -      _picture_asset->set_directory (_film->dir (_film->dcp_name ()));
 -      _picture_asset->set_file_name (_film->video_mxf_filename ());
 +      _picture_mxf->set_file (video_to);
  
        /* Move the audio MXF into the DCP */
  
        assert (job);
  
        job->sub (_("Computing image digest"));
 -      _picture_asset->compute_digest (boost::bind (&Job::set_progress, job.get(), _1, false));
 +      _picture_mxf->hash (boost::bind (&Job::set_progress, job.get(), _1, false));
  
 -      if (_sound_asset) {
 +      if (_sound_mxf) {
                job->sub (_("Computing audio digest"));
 -              _sound_asset->compute_digest (boost::bind (&Job::set_progress, job.get(), _1, false));
 +              _sound_mxf->hash (boost::bind (&Job::set_progress, job.get(), _1, false));
        }
  
 -      libdcp::XMLMetadata meta = Config::instance()->dcp_metadata ();
 +      dcp::XMLMetadata meta = Config::instance()->dcp_metadata ();
        meta.set_issue_date_now ();
 -      dcp.write_xml (_film->interop (), meta, _film->is_signed() ? make_signer () : shared_ptr<const libdcp::Signer> ());
 +
 +      dcp.write_xml (_film->interop () ? dcp::INTEROP : dcp::SMPTE, meta, _film->is_signed() ? make_signer () : shared_ptr<const dcp::Signer> ());
  
-       _film->log()->log (
-               String::compose (N_("Wrote %1 FULL, %2 FAKE, %3 pushed to disk"), _full_written, _fake_written, _pushed_to_disk)
+       LOG_GENERAL (
 -              N_("Wrote %1 FULL, %2 FAKE, %3 REPEAT; %4 pushed to disk"), _full_written, _fake_written, _repeat_written, _pushed_to_disk
++              N_("Wrote %1 FULL, %2 FAKE, %3 pushed to disk"), _full_written, _fake_written, _pushed_to_disk
                );
  }
  
@@@ -475,10 -509,10 +478,10 @@@ Writer::check_existing_picture_mxf_fram
                return false;
        }
        
 -      libdcp::FrameInfo info (ifi);
 +      dcp::FrameInfo info (ifi);
        fclose (ifi);
        if (info.size == 0) {
-               _film->log()->log (String::compose ("Existing frame %1 has no info file", f));
+               LOG_GENERAL ("Existing frame %1 has no info file", f);
                return false;
        }
        
Simple merge
Simple merge
index 2f6916df2be684ae5569e30a73af3922eaba3c72,041f6c7ef295d1a9100454fa7d25cfb0a6e87991..0f2d5b8a31ad5e6c757a27d8702a1fe0d396726e
@@@ -234,8 -235,8 +235,8 @@@ int main (int argc, char* argv[]
                        error ("you must specify --output");
                }
                
 -              shared_ptr<libdcp::Certificate> certificate (new libdcp::Certificate (boost::filesystem::path (certificate_file)));
 -              libdcp::KDM kdm = film->make_kdm (certificate, cpl, valid_from.get(), valid_to.get());
 +              shared_ptr<dcp::Certificate> certificate (new dcp::Certificate (boost::filesystem::path (certificate_file)));
-               dcp::EncryptedKDM kdm = film->make_kdm (certificate, dcp, valid_from.get(), valid_to.get());
++              dcp::EncryptedKDM kdm = film->make_kdm (certificate, cpl, valid_from.get(), valid_to.get());
                kdm.as_xml (output);
                if (verbose) {
                        cout << "Generated KDM " << output << " for certificate.\n";
  
                try {
                        if (zip) {
-                               write_kdm_zip_files (film, (*i)->screens(), dcp, dcp::LocalTime (valid_from.get()), dcp::LocalTime (valid_to.get()), output);
 -                              write_kdm_zip_files (film, (*i)->screens(), cpl, valid_from.get(), valid_to.get(), output);
++                              write_kdm_zip_files (film, (*i)->screens(), cpl, dcp::LocalTime (valid_from.get()), dcp::LocalTime (valid_to.get()), output);
++
                                if (verbose) {
                                        cout << "Wrote ZIP files to " << output << "\n";
                                }
                        } else {
-                               write_kdm_files (film, (*i)->screens(), dcp, dcp::LocalTime (valid_from.get()), dcp::LocalTime (valid_to.get()), output);
 -                              write_kdm_files (film, (*i)->screens(), cpl, valid_from.get(), valid_to.get(), output);
++                              write_kdm_files (film, (*i)->screens(), cpl, dcp::LocalTime (valid_from.get()), dcp::LocalTime (valid_to.get()), output);
                                if (verbose) {
                                        cout << "Wrote KDM files to " << output << "\n";
                                }
Simple merge
Simple merge
Simple merge
index 8e4fb0e1867e845e644864012eae8812b2468183,98993cc5bd67c5148870e38245ff56db6da5864e..c0eddd8f6a7f8eee16dcbbef3d27119a2cf45898
@@@ -78,12 -70,14 +78,14 @@@ BOOST_AUTO_TEST_CASE (client_server_tes
                p += sub_image->stride()[0];
        }
  
+       shared_ptr<FileLog> log (new FileLog ("build/test/client_server_test.log"));
        shared_ptr<PlayerVideoFrame> pvf (
                new PlayerVideoFrame (
-                       shared_ptr<ImageProxy> (new RawImageProxy (image)),
+                       shared_ptr<ImageProxy> (new RawImageProxy (image, log)),
                        Crop (),
 -                      libdcp::Size (1998, 1080),
 -                      libdcp::Size (1998, 1080),
 +                      dcp::Size (1998, 1080),
 +                      dcp::Size (1998, 1080),
                        Scaler::from_id ("bicubic"),
                        EYES_BOTH,
                        PART_WHOLE,
                        )
                );
  
 -      pvf->set_subtitle (sub_image, Position<int> (50, 60));
 +      pvf->set_subtitle (PositionImage (sub_image, Position<int> (50, 60)));
  
-       shared_ptr<FileLog> log (new FileLog ("build/test/client_server_test.log"));
        shared_ptr<DCPVideoFrame> frame (
                new DCPVideoFrame (
                        pvf,
Simple merge